Merge remote-tracking branch 'upstream/master' into psel-libapplet

This commit is contained in:
XorTroll 2019-10-10 19:08:53 +02:00
commit 304cbe735d
93 changed files with 8449 additions and 13147 deletions

View File

@ -1,5 +1,100 @@
# Changelog # Changelog
## Version 2.5.0
#### system
* Corrected type of id0 in svcGetInfo.
#### filesystem
* Added fsExtendSaveDataFileSystem, fsOpenCustomStorageFileSystem, fsSetGlobalAccessLogMode, fsGetGlobalAccessLogMode.
* Added FsCustomStorageId enum.
* Fixed by-name RomFS mount lookups to actually compare the entire name.
#### graphics
* Added binder session argument to nwindowCreate (nwindowCreateFromLayer not affected).
* Binder code now supports domain objects.
* Fixed bug in nvAddressSpaceCreate.
#### input
* **Explicitly announce support for System/SystemExt layouts, which in turn fixes input on 9.0.0+. It is of utmost importance that all homebrew be recompiled as soon as possible in order to work properly on 9.0.0+.**
* **Fixed Hdls to work on 9.0.0+.**
* Several Hdls structs were redefined in 9.0.0+ and libnx was updated to reflect the new struct definitions (this is a breaking change). The old structs are still available but they now have a `V7` suffix, and libnx transparently handles conversion to/from the new 9.x structs at runtime on older system versions; so the new structs are *always* used regardless of system version. List of structs affected:
* HiddbgHdlsDeviceInfo(V7)
* HiddbgHdlsState(V7)
* HiddbgHdlsStateListEntry(V7)
* HiddbgHdlsStateList(V7)
* Added hiddbgGetUniquePadDeviceTypeSetInternal.
* Added hidGetNpadInterfaceType.
* Added HidNpadInterfaceType, HidDeviceTypeBits, HidDeviceType enums.
* Prevent AbstractedPad/VirtualPad commands from being used on 9.0.0+ since they were removed.
* Corrected several commands by internally calling hidControllerIDToOfficial.
#### applet
* Added AppletAttribute, AppletProcessLaunchReason, AppletInfo, AppletApplicationLaunchProperty, AppletApplicationLaunchRequestInfo, AppletResourceUsageInfo structs.
* Added AppletApplicationExitReason, AppletSystemButtonType, AppletProgramSpecifyKind enums.
* Renamed AppletNotificationMessage to AppletMessage.
* Renamed AppletLaunchParameterKind_Application to AppletLaunchParameterKind_UserChannel.
* Added appletGetServiceSession_* funcs.
* Added appletGetAppletInfo.
* Changed appletRequestToShutdown/appletRequestToReboot and appletStartShutdownSequenceForOverlay/appletStartRebootSequenceForOverlay on success to enter an infinite sleep loop.
* This is also used with `_appletExitProcess` when the exit commands were successful, which is used during `__nx_applet_exit_mode` handling.
* Use OpenLibraryAppletProxy command on 3.0.0+ when running appletInitialize for AppletType_LibraryApplet.
* Added libappletArgsPop and libappletSetJumpFlag.
* **ILibraryAppletSelfAccessor**:
* Added appletPopInData, appletPushOutData, appletPopInteractiveInData, appletPushInteractiveOutData, appletGetPopInDataEvent, appletGetPopInteractiveInDataEvent.
* Added appletCanUseApplicationCore, appletGetMainAppletApplicationControlProperty, appletGetMainAppletStorageId, appletGetDesirableKeyboardLayout.
* Added appletPopExtraStorage, appletGetPopExtraStorageEvent, appletUnpopInData, appletUnpopExtraStorage.
* Added appletGetIndirectLayerProducerHandle, appletGetMainAppletApplicationDesiredLanguage, appletGetCurrentApplicationId.
* Added appletCreateGameMovieTrimmer, appletReserveResourceForMovieOperation, appletUnreserveResourceForMovieOperation.
* Added appletGetMainAppletAvailableUsers.
* **IProcessWindingController**:
* Added appletPushContext, appletPopContext.
* **IDebugFunctions**:
* Added appletOpenMainApplication, appletPerformSystemButtonPressing, appletInvalidateTransitionLayer, appletRequestLaunchApplicationWithUserAndArgumentForDebug, appletGetAppletResourceUsageInfo.
* **ILibraryAppletAccessor**:
* Added appletHolderTerminate, appletHolderRequestExitOrTerminate.
* **IProcessWindingController**:
* Added appletHolderJump.
* **IOverlayFunctions**:
* Added appletBeginToObserveHidInputForDevelop.
* **IHomeMenuFunctions**:
* Added appletPopRequestLaunchApplicationForDebug, appletLaunchDevMenu.
* **IApplicationCreator**:
* Added support for AppletApplication.
* Added appletCreateApplication, appletPopLaunchRequestedApplication, appletCreateSystemApplication, appletPopFloatingApplicationForDevelopment.
* **ILibraryAppletCreator**:
* Added appletTerminateAllLibraryApplets, appletAreAnyLibraryAppletsLeft.
* **IApplicationFunctions**:
* Added appletGetLaunchStorageInfoForDebug, appletRequestFlushGamePlayingMovieForDebug, appletExitAndRequestToShowThanksMessage.
* Added appletExecuteProgram, appletJumpToSubApplicationProgramForDevelopment, appletRestartProgram, and appletGetPreviousProgramIndex.
* Added appletCreateMovieMaker and appletPrepareForJit.
#### libapplets
* Added support for launching the Album applet via albumLa.
#### other services
* **Added GRC service support** (video recording, streaming and trimming).
* Changes to caps (capture service) wrappers:
* Added support for the caps:u service.
* Added CapsAlbumFileDateTime, CapsAlbumEntryId, CapsApplicationData, CapsUserIdList, CapsScreenShotAttributeForApplication, CapsScreenShotDecodeOption, CapsApplicationAlbumFileEntry, CapsLoadAlbumScreenShotImageOutputForApplication structs.
* Added AlbumReportOption, CapsContentType enums.
* Added capsGetShimLibraryVersion (not an actual IPC wrapper).
* Added capsGetDefaultStartDateTime, capsGetDefaultEndDateTime, capsConvertApplicationAlbumFileEntryToApplicationAlbumEntry, capsConvertApplicationAlbumEntryToApplicationAlbumFileEntry helper functions.
* Added capssuSaveScreenShotWithUserData, capssuSaveScreenShotWithUserIds, capssuSaveScreenShotEx1, capssuSaveScreenShotEx2.
* Improved definition of capssuSaveScreenShot and capssuSaveScreenShotEx0.
* Improved definition of CapsScreenShotAttribute, CapsApplicationAlbumEntry structs.
* Changed caps:su wrapper to call SetShimLibraryVersion on 7.0.0+.
* Renamed capsscCaptureScreenshot with capsscCaptureRawImageWithTimeout.
* Fixed lr RedirectApplication commands on 9.0.0+.
* Renamed lrLrResolveLegalInformationPath to lrLrResolveApplicationLegalInformationPath.
* Renamed lrLrRedirectLegalInformationPath to lrLrRedirectApplicationLegalInformationPath.
* Added missing fields to NacpStruct and other miscellaneous corrections.
* Fixed definition of setsysGetServiceSession.
#### miscellaneous
* Further improvements to overall system stability and other minor adjustments have been made to enhance the user experience.
## Version 2.4.0 ## Version 2.4.0
#### system #### system

View File

@ -9,7 +9,7 @@ endif
include $(DEVKITPRO)/devkitA64/base_rules include $(DEVKITPRO)/devkitA64/base_rules
export LIBNX_MAJOR := 2 export LIBNX_MAJOR := 2
export LIBNX_MINOR := 4 export LIBNX_MINOR := 5
export LIBNX_PATCH := 0 export LIBNX_PATCH := 0
@ -39,7 +39,7 @@ CFLAGS := -g -Wall -Werror \
$(ARCH) \ $(ARCH) \
$(BUILD_CFLAGS) $(BUILD_CFLAGS)
CFLAGS += $(INCLUDE) -DSWITCH CFLAGS += $(INCLUDE) -D__SWITCH__ -DLIBNX_NO_DEPRECATION
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11

View File

@ -36,9 +36,13 @@ extern "C" {
#include "switch/kernel/detect.h" #include "switch/kernel/detect.h"
#include "switch/kernel/random.h" #include "switch/kernel/random.h"
#include "switch/kernel/jit.h" #include "switch/kernel/jit.h"
#include "switch/kernel/ipc.h" #include "switch/kernel/ipc.h" // Deprecated
#include "switch/kernel/barrier.h" #include "switch/kernel/barrier.h"
#include "switch/sf/hipc.h"
#include "switch/sf/cmif.h"
#include "switch/sf/service.h"
#include "switch/services/sm.h" #include "switch/services/sm.h"
#include "switch/services/smm.h" #include "switch/services/smm.h"
#include "switch/services/fs.h" #include "switch/services/fs.h"
@ -47,6 +51,7 @@ extern "C" {
#include "switch/services/acc.h" #include "switch/services/acc.h"
#include "switch/services/apm.h" #include "switch/services/apm.h"
#include "switch/services/applet.h" #include "switch/services/applet.h"
#include "switch/services/async.h"
#include "switch/services/audin.h" #include "switch/services/audin.h"
#include "switch/services/audout.h" #include "switch/services/audout.h"
#include "switch/services/audren.h" #include "switch/services/audren.h"
@ -78,6 +83,7 @@ extern "C" {
#include "switch/services/ns.h" #include "switch/services/ns.h"
#include "switch/services/ldr.h" #include "switch/services/ldr.h"
#include "switch/services/ro.h" #include "switch/services/ro.h"
#include "switch/services/ts.h"
#include "switch/services/pm.h" #include "switch/services/pm.h"
#include "switch/services/set.h" #include "switch/services/set.h"
#include "switch/services/lr.h" #include "switch/services/lr.h"
@ -85,6 +91,7 @@ extern "C" {
#include "switch/services/ncm.h" #include "switch/services/ncm.h"
#include "switch/services/psc.h" #include "switch/services/psc.h"
#include "switch/services/caps.h" #include "switch/services/caps.h"
#include "switch/services/capsu.h"
#include "switch/services/capssc.h" #include "switch/services/capssc.h"
#include "switch/services/capssu.h" #include "switch/services/capssu.h"
#include "switch/services/nfc.h" #include "switch/services/nfc.h"
@ -92,6 +99,7 @@ extern "C" {
#include "switch/services/pctl.h" #include "switch/services/pctl.h"
#include "switch/services/pdm.h" #include "switch/services/pdm.h"
#include "switch/services/grc.h" #include "switch/services/grc.h"
#include "switch/services/friends.h"
#include "switch/display/binder.h" #include "switch/display/binder.h"
#include "switch/display/parcel.h" #include "switch/display/parcel.h"
@ -111,6 +119,8 @@ extern "C" {
#include "switch/audio/driver.h" #include "switch/audio/driver.h"
#include "switch/applets/libapplet.h" #include "switch/applets/libapplet.h"
#include "switch/applets/album_la.h"
#include "switch/applets/friends_la.h"
#include "switch/applets/pctlauth.h" #include "switch/applets/pctlauth.h"
#include "switch/applets/psel.h" #include "switch/applets/psel.h"
#include "switch/applets/error.h" #include "switch/applets/error.h"

View File

@ -0,0 +1,31 @@
/**
* @file album_la.h
* @brief Wrapper for using the Album LibraryApplet.
* @author yellows8
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
/// Arg type values pushed for the applet input storage, stored as an u8.
typedef enum {
AlbumLaArg_ShowAlbumFiles = 0, ///< ShowAlbumFiles. Only displays AlbumFiles associated with the title which launched the Album applet, with the filter button disabled.
AlbumLaArg_ShowAllAlbumFiles = 1, ///< ShowAllAlbumFiles. Displays all AlbumFiles, with filtering allowed.
AlbumLaArg_ShowAllAlbumFilesForHomeMenu = 2, ///< ShowAllAlbumFilesForHomeMenu. Similar to ::AlbumLaArg_ShowAllAlbumFiles.
} AlbumLaArg;
/**
* @brief Launches the applet with ::AlbumLaArg_ShowAlbumFiles and playStartupSound=false.
*/
Result albumLaShowAlbumFiles(void);
/**
* @brief Launches the applet with ::AlbumLaArg_ShowAllAlbumFiles and playStartupSound=false.
*/
Result albumLaShowAllAlbumFiles(void);
/**
* @brief Launches the applet with ::AlbumLaArg_ShowAllAlbumFilesForHomeMenu and playStartupSound=true.
*/
Result albumLaShowAllAlbumFilesForHomeMenu(void);

View File

@ -0,0 +1,94 @@
/**
* @file friends_la.h
* @brief Wrapper for using the MyPage (friends) LibraryApplet.
* @author yellows8
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../services/acc.h"
#include "../services/friends.h"
/// Arg type values used with \ref FriendsLaArg.
typedef enum {
FriendsLaArgType_ShowFriendList = 0, ///< ShowFriendList. Launches the applet with the "Friend List" menu initially selected.
FriendsLaArgType_ShowUserDetailInfo = 1, ///< ShowUserDetailInfo
FriendsLaArgType_StartSendingFriendRequest = 2, ///< StartSendingFriendRequest
FriendsLaArgType_ShowMethodsOfSendingFriendRequest = 3, ///< ShowMethodsOfSendingFriendRequest. Launches the applet with the "Add Friend" menu initially selected.
FriendsLaArgType_StartFacedFriendRequest = 4, ///< StartFacedFriendRequest. Launches the applet where the "Search for Local Users" menu is initially shown. Returning from this menu will exit the applet.
FriendsLaArgType_ShowReceivedFriendRequestList = 5, ///< ShowReceivedFriendRequestList. Launches the applet where the "Received Friend Requests" menu is initially shown. Returning from this menu will exit the applet.
FriendsLaArgType_ShowBlockedUserList = 6, ///< ShowBlockedUserList. Launches the applet where the "Blocked-User List" menu is initially shown. Returning from this menu will exit the applet.
FriendsLaArgType_ShowMyProfile = 7, ///< ShowMyProfile. Launches the applet with the "Profile" menu initially selected. ShowMyProfileForHomeMenu is identical to this except for playStartupSound=true.
} FriendsLaArgType;
/// Arg struct pushed for the applet input storage.
/// The fields following the userID are only set for ::FriendsLaArgType_ShowUserDetailInfo/::FriendsLaArgType_StartSendingFriendRequest, for everything else these are cleared.
typedef struct {
u32 type; ///< \ref FriendsLaArgType
u32 pad; ///< Padding.
AccountUid userID; ///< \ref AccountUid
u64 networkServiceAccountId; ///< NetworkServiceAccountId for the other account.
FriendsInAppScreenName first_inAppScreenName; ///< First InAppScreenName.
FriendsInAppScreenName second_inAppScreenName; ///< Second InAppScreenName.
} FriendsLaArg;
/**
* @brief Launches the applet with ::FriendsLaArgType_ShowFriendList, the specified input, and playStartupSound=false.
* @param[in] userID \ref AccountUid
*/
Result friendsLaShowFriendList(AccountUid *userID);
/**
* @brief Launches the applet with ::FriendsLaArgType_ShowUserDetailInfo, the specified input, and playStartupSound=false.
* @param[in] userID \ref AccountUid
* @param[in] networkServiceAccountId NetworkServiceAccountId for the user to show UserDetailInfo for.
* @param[in] first_inAppScreenName First \ref FriendsInAppScreenName.
* @param[in] second_inAppScreenName Second \ref FriendsInAppScreenName.
*/
Result friendsLaShowUserDetailInfo(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName);
/**
* @brief Launches the applet with ::FriendsLaArgType_StartSendingFriendRequest, the specified input, and playStartupSound=false. On success, this will load the output Result from the output storage.
* @param[in] userID \ref AccountUid
* @param[in] networkServiceAccountId NetworkServiceAccountId to send the friend request to.
* @param[in] first_inAppScreenName First \ref FriendsInAppScreenName.
* @param[in] second_inAppScreenName Second \ref FriendsInAppScreenName.
*/
Result friendsLaStartSendingFriendRequest(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName);
/**
* @brief Launches the applet with ::FriendsLaArgType_ShowMethodsOfSendingFriendRequest, the specified input, and playStartupSound=false.
* @param[in] userID \ref AccountUid
*/
Result friendsLaShowMethodsOfSendingFriendRequest(AccountUid *userID);
/**
* @brief Launches the applet with ::FriendsLaArgType_StartFacedFriendRequest, the specified input, and playStartupSound=false.
* @param[in] userID \ref AccountUid
*/
Result friendsLaStartFacedFriendRequest(AccountUid *userID);
/**
* @brief Launches the applet with ::FriendsLaArgType_ShowReceivedFriendRequestList, the specified input, and playStartupSound=false.
* @param[in] userID \ref AccountUid
*/
Result friendsLaShowReceivedFriendRequestList(AccountUid *userID);
/**
* @brief Launches the applet with ::FriendsLaArgType_ShowBlockedUserList, the specified input, and playStartupSound=false.
* @param[in] userID \ref AccountUid
*/
Result friendsLaShowBlockedUserList(AccountUid *userID);
/**
* @brief Launches the applet with ::FriendsLaArgType_ShowMyProfile, the specified input, and playStartupSound=false.
* @param[in] userID \ref AccountUid
*/
Result friendsLaShowMyProfile(AccountUid *userID);
/**
* @brief Same as \ref friendsLaShowMyProfile except with playStartupSound=true.
* @param[in] userID \ref AccountUid
*/
Result friendsLaShowMyProfileForHomeMenu(AccountUid *userID);

View File

@ -197,12 +197,13 @@ typedef struct {
s32 unk_x20; s32 unk_x20;
s32 unk_x24; s32 unk_x24;
u8 returnButtonFlag; ///< Controls whether the Return button is enabled, for newlines input. 0 = disabled, non-zero = enabled. u8 returnButtonFlag; ///< Controls whether the Return button is enabled, for newlines input. 0 = disabled, non-zero = enabled.
u16 unk_x29; u8 unk_x29;
u8 unk_x2a;
u8 unk_x2b; u8 unk_x2b;
u32 flags; ///< Bitmask 0x4: unknown. u32 flags; ///< Bitmask 0x4: unknown.
u8 unk_x30; u8 unk_x30;
u8 unk_x31[0x17]; u8 unk_x31[0x17];
} PACKED SwkbdAppearArg; } SwkbdAppearArg;
typedef struct { typedef struct {
u32 unk_x0; u32 unk_x0;
@ -226,7 +227,8 @@ typedef struct {
u8 disableTouch; ///< Flags bitmask 0x200. u8 disableTouch; ///< Flags bitmask 0x200.
u8 disableUSBKeyboard; ///< Flags bitmask 0x800. u8 disableUSBKeyboard; ///< Flags bitmask 0x800.
u8 unk_x468[5]; u8 unk_x468[5];
u16 unk_x46d; u8 unk_x46d;
u8 unk_x46e;
u8 unk_x46f; u8 unk_x46f;
float keytopScaleX; ///< Flags bitmask 0x200. float keytopScaleX; ///< Flags bitmask 0x200.
float keytopScaleY; ///< Flags bitmask 0x200. float keytopScaleY; ///< Flags bitmask 0x200.
@ -241,7 +243,7 @@ typedef struct {
u8 triggerFlag; ///< [6.0.0+] Enables using the trigger field when set. u8 triggerFlag; ///< [6.0.0+] Enables using the trigger field when set.
u8 trigger; ///< [6.0.0+] Trigger u8 trigger; ///< [6.0.0+] Trigger
u8 pad_x49f; u8 pad_x49f;
} PACKED SwkbdInlineCalcArg; } SwkbdInlineCalcArg;
/// Struct data for SwkbdInline Interactive reply storage ChangedString*, at the end following the string. /// Struct data for SwkbdInline Interactive reply storage ChangedString*, at the end following the string.
typedef struct { typedef struct {

View File

@ -8,6 +8,7 @@
#include "../types.h" #include "../types.h"
#include "../services/applet.h" #include "../services/applet.h"
#include "../services/caps.h" #include "../services/caps.h"
#include "../services/acc.h"
/// This indicates the type of web-applet. /// This indicates the type of web-applet.
typedef enum { typedef enum {
@ -126,7 +127,7 @@ typedef enum {
WebArgType_NewsFlag = 0xB, ///< [1.0.0+] u8 bool WebArgType_NewsFlag = 0xB, ///< [1.0.0+] u8 bool
WebArgType_UnknownC = 0xC, ///< [1.0.0+] u8 WebArgType_UnknownC = 0xC, ///< [1.0.0+] u8
WebArgType_UnknownD = 0xD, ///< [1.0.0+] u8 WebArgType_UnknownD = 0xD, ///< [1.0.0+] u8
WebArgType_UserID = 0xE, ///< [1.0.0+] u128 userID, controls which user-specific savedata to mount. WebArgType_Uid = 0xE, ///< [1.0.0+] \ref AccountUid, controls which user-specific savedata to mount.
WebArgType_AlbumEntry0 = 0xF, ///< [1.0.0+] Share-applet caps AlbumEntry, entry 0. WebArgType_AlbumEntry0 = 0xF, ///< [1.0.0+] Share-applet caps AlbumEntry, entry 0.
WebArgType_ScreenShot = 0x10, ///< [1.0.0+] u8 bool WebArgType_ScreenShot = 0x10, ///< [1.0.0+] u8 bool
WebArgType_EcClientCert = 0x11, ///< [1.0.0+] u8 bool WebArgType_EcClientCert = 0x11, ///< [1.0.0+] u8 bool
@ -344,9 +345,9 @@ Result webConfigSetWhitelist(WebCommonConfig* config, const char* whitelist);
* @note Only available with config created by \ref webPageCreate, \ref webLobbyCreate, or with Share-applet. * @note Only available with config created by \ref webPageCreate, \ref webLobbyCreate, or with Share-applet.
* @note Used automatically by \ref webShareCreate and \ref webLobbyCreate with userID=0. * @note Used automatically by \ref webShareCreate and \ref webLobbyCreate with userID=0.
* @param config WebCommonConfig object. * @param config WebCommonConfig object.
* @param userID Account userID * @param uid \ref AccountUid
*/ */
Result webConfigSetUserID(WebCommonConfig* config, u128 userID); Result webConfigSetUid(WebCommonConfig* config, AccountUid *uid);
/** /**
* @brief Sets the Share CapsAlbumEntry. * @brief Sets the Share CapsAlbumEntry.

View File

@ -8,6 +8,7 @@
#include "../types.h" #include "../types.h"
/// PcmFormat
typedef enum { typedef enum {
PcmFormat_Invalid = 0, PcmFormat_Invalid = 0,
PcmFormat_Int8 = 1, PcmFormat_Int8 = 1,
@ -18,6 +19,7 @@ typedef enum {
PcmFormat_Adpcm = 6, PcmFormat_Adpcm = 6,
} PcmFormat; } PcmFormat;
/// AudioDeviceName
typedef struct { typedef struct {
char name[0x100]; char name[0x100];
} AudioDeviceName; } AudioDeviceName;

View File

@ -10,7 +10,7 @@ typedef struct {
bool initialized : 1; bool initialized : 1;
bool has_transact_auto : 1; bool has_transact_auto : 1;
s32 id; s32 id;
size_t ipc_buffer_size; size_t dummy;
Service* relay; Service* relay;
} Binder; } Binder;

View File

@ -9,6 +9,9 @@
#include "../arm/tls.h" #include "../arm/tls.h"
#include "../kernel/svc.h" #include "../kernel/svc.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/// IPC input header magic /// IPC input header magic
#define SFCI_MAGIC 0x49434653 #define SFCI_MAGIC 0x49434653
/// IPC output header magic /// IPC output header magic
@ -29,13 +32,13 @@ typedef enum {
BufferType_Type1=1, ///< Allows ProcessMemory and shared TransferMemory. BufferType_Type1=1, ///< Allows ProcessMemory and shared TransferMemory.
BufferType_Invalid=2, BufferType_Invalid=2,
BufferType_Type3=3 ///< Same as Type1 except remote process is not allowed to use device-mapping. BufferType_Type3=3 ///< Same as Type1 except remote process is not allowed to use device-mapping.
} BufferType; } BufferType DEPRECATED;
typedef enum { typedef enum {
BufferDirection_Send=0, BufferDirection_Send=0,
BufferDirection_Recv=1, BufferDirection_Recv=1,
BufferDirection_Exch=2, BufferDirection_Exch=2,
} BufferDirection; } BufferDirection DEPRECATED;
typedef enum { typedef enum {
IpcCommandType_Invalid = 0, IpcCommandType_Invalid = 0,
@ -46,13 +49,13 @@ typedef enum {
IpcCommandType_Control = 5, IpcCommandType_Control = 5,
IpcCommandType_RequestWithContext = 6, IpcCommandType_RequestWithContext = 6,
IpcCommandType_ControlWithContext = 7, IpcCommandType_ControlWithContext = 7,
} IpcCommandType; } IpcCommandType DEPRECATED;
typedef enum { typedef enum {
DomainMessageType_Invalid = 0, DomainMessageType_Invalid = 0,
DomainMessageType_SendMessage = 1, DomainMessageType_SendMessage = 1,
DomainMessageType_Close = 2, DomainMessageType_Close = 2,
} DomainMessageType; } DomainMessageType DEPRECATED;
/// IPC domain message header. /// IPC domain message header.
typedef struct { typedef struct {
@ -61,13 +64,13 @@ typedef struct {
u16 Length; u16 Length;
u32 ThisObjectId; u32 ThisObjectId;
u32 Pad[2]; u32 Pad[2];
} DomainMessageHeader; } DomainMessageHeader DEPRECATED;
/// IPC domain response header. /// IPC domain response header.
typedef struct { typedef struct {
u32 NumObjectIds; u32 NumObjectIds;
u32 Pad[3]; u32 Pad[3];
} DomainResponseHeader; } DomainResponseHeader DEPRECATED;
typedef struct { typedef struct {
@ -91,12 +94,13 @@ typedef struct {
size_t NumObjectIds; size_t NumObjectIds;
u32 ObjectIds[IPC_MAX_OBJECTS]; u32 ObjectIds[IPC_MAX_OBJECTS];
} IpcCommand; } IpcCommand DEPRECATED;
/** /**
* @brief Initializes an IPC command structure. * @brief Initializes an IPC command structure.
* @param cmd IPC command structure. * @param cmd IPC command structure.
*/ */
DEPRECATED
static inline void ipcInitialize(IpcCommand* cmd) { static inline void ipcInitialize(IpcCommand* cmd) {
*cmd = (IpcCommand){}; *cmd = (IpcCommand){};
} }
@ -106,19 +110,19 @@ typedef struct {
u32 Size; ///< Size of the buffer. u32 Size; ///< Size of the buffer.
u32 Addr; ///< Lower 32-bits of the address of the buffer u32 Addr; ///< Lower 32-bits of the address of the buffer
u32 Packed; ///< Packed data (including higher bits of the address) u32 Packed; ///< Packed data (including higher bits of the address)
} IpcBufferDescriptor; } IpcBufferDescriptor DEPRECATED;
/// IPC static send-buffer descriptor. /// IPC static send-buffer descriptor.
typedef struct { typedef struct {
u32 Packed; ///< Packed data (including higher bits of the address) u32 Packed; ///< Packed data (including higher bits of the address)
u32 Addr; ///< Lower 32-bits of the address u32 Addr; ///< Lower 32-bits of the address
} IpcStaticSendDescriptor; } IpcStaticSendDescriptor DEPRECATED;
/// IPC static receive-buffer descriptor. /// IPC static receive-buffer descriptor.
typedef struct { typedef struct {
u32 Addr; ///< Lower 32-bits of the address of the buffer u32 Addr; ///< Lower 32-bits of the address of the buffer
u32 Packed; ///< Packed data (including higher bits of the address) u32 Packed; ///< Packed data (including higher bits of the address)
} IpcStaticRecvDescriptor; } IpcStaticRecvDescriptor DEPRECATED;
/** /**
* @brief Adds a buffer to an IPC command structure. * @brief Adds a buffer to an IPC command structure.
@ -127,6 +131,7 @@ typedef struct {
* @param size Size of the buffer. * @param size Size of the buffer.
* @param type Buffer type. * @param type Buffer type.
*/ */
DEPRECATED
static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, BufferType type) { static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t size, BufferType type) {
size_t off = cmd->NumSend; size_t off = cmd->NumSend;
cmd->Buffers[off] = buffer; cmd->Buffers[off] = buffer;
@ -142,6 +147,7 @@ static inline void ipcAddSendBuffer(IpcCommand* cmd, const void* buffer, size_t
* @param size Size of the buffer. * @param size Size of the buffer.
* @param type Buffer type. * @param type Buffer type.
*/ */
DEPRECATED
static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) { static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
size_t off = cmd->NumSend + cmd->NumRecv; size_t off = cmd->NumSend + cmd->NumRecv;
cmd->Buffers[off] = buffer; cmd->Buffers[off] = buffer;
@ -157,6 +163,7 @@ static inline void ipcAddRecvBuffer(IpcCommand* cmd, void* buffer, size_t size,
* @param size Size of the buffer. * @param size Size of the buffer.
* @param type Buffer type. * @param type Buffer type.
*/ */
DEPRECATED
static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) { static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size, BufferType type) {
size_t off = cmd->NumSend + cmd->NumRecv + cmd->NumExch; size_t off = cmd->NumSend + cmd->NumRecv + cmd->NumExch;
cmd->Buffers[off] = buffer; cmd->Buffers[off] = buffer;
@ -172,6 +179,7 @@ static inline void ipcAddExchBuffer(IpcCommand* cmd, void* buffer, size_t size,
* @param size Size of the buffer. * @param size Size of the buffer.
* @param index Index of buffer. * @param index Index of buffer.
*/ */
DEPRECATED
static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index) { static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t size, u8 index) {
size_t off = cmd->NumStaticIn; size_t off = cmd->NumStaticIn;
cmd->Statics[off] = buffer; cmd->Statics[off] = buffer;
@ -187,6 +195,7 @@ static inline void ipcAddSendStatic(IpcCommand* cmd, const void* buffer, size_t
* @param size Size of the buffer. * @param size Size of the buffer.
* @param index Index of buffer. * @param index Index of buffer.
*/ */
DEPRECATED
static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index) { static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size, u8 index) {
size_t off = cmd->NumStaticIn + cmd->NumStaticOut; size_t off = cmd->NumStaticIn + cmd->NumStaticOut;
cmd->Statics[off] = buffer; cmd->Statics[off] = buffer;
@ -203,6 +212,7 @@ static inline void ipcAddRecvStatic(IpcCommand* cmd, void* buffer, size_t size,
* @param size Size of the buffer. * @param size Size of the buffer.
* @param index Index of buffer. * @param index Index of buffer.
*/ */
DEPRECATED
static inline void ipcAddSendSmart(IpcCommand* cmd, size_t pointer_buffer_size, const void* buffer, size_t size, u8 index) { static inline void ipcAddSendSmart(IpcCommand* cmd, size_t pointer_buffer_size, const void* buffer, size_t size, u8 index) {
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) { if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
ipcAddSendBuffer(cmd, NULL, 0, BufferType_Normal); ipcAddSendBuffer(cmd, NULL, 0, BufferType_Normal);
@ -221,6 +231,7 @@ static inline void ipcAddSendSmart(IpcCommand* cmd, size_t pointer_buffer_size,
* @param size Size of the buffer. * @param size Size of the buffer.
* @param index Index of buffer. * @param index Index of buffer.
*/ */
DEPRECATED
static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t pointer_buffer_size, void* buffer, size_t size, u8 index) { static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t pointer_buffer_size, void* buffer, size_t size, u8 index) {
if (pointer_buffer_size != 0 && size <= pointer_buffer_size) { if (pointer_buffer_size != 0 && size <= pointer_buffer_size) {
ipcAddRecvBuffer(cmd, NULL, 0, BufferType_Normal); ipcAddRecvBuffer(cmd, NULL, 0, BufferType_Normal);
@ -235,6 +246,7 @@ static inline void ipcAddRecvSmart(IpcCommand* cmd, size_t pointer_buffer_size,
* @brief Tags an IPC command structure to send the PID. * @brief Tags an IPC command structure to send the PID.
* @param cmd IPC command structure. * @param cmd IPC command structure.
*/ */
DEPRECATED
static inline void ipcSendPid(IpcCommand* cmd) { static inline void ipcSendPid(IpcCommand* cmd) {
cmd->SendPid = true; cmd->SendPid = true;
} }
@ -245,6 +257,7 @@ static inline void ipcSendPid(IpcCommand* cmd) {
* @param h Handle to send. * @param h Handle to send.
* @remark The receiving process gets a copy of the handle. * @remark The receiving process gets a copy of the handle.
*/ */
DEPRECATED
static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) { static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) {
cmd->Handles[cmd->NumHandlesCopy++] = h; cmd->Handles[cmd->NumHandlesCopy++] = h;
} }
@ -255,6 +268,7 @@ static inline void ipcSendHandleCopy(IpcCommand* cmd, Handle h) {
* @param h Handle to send. * @param h Handle to send.
* @remark The sending process loses ownership of the handle, which is transferred to the receiving process. * @remark The sending process loses ownership of the handle, which is transferred to the receiving process.
*/ */
DEPRECATED
static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) { static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) {
cmd->Handles[cmd->NumHandlesCopy + cmd->NumHandlesMove++] = h; cmd->Handles[cmd->NumHandlesCopy + cmd->NumHandlesMove++] = h;
} }
@ -265,6 +279,7 @@ static inline void ipcSendHandleMove(IpcCommand* cmd, Handle h) {
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request * @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
* @return Pointer to the raw embedded data structure in the request, ready to be filled out. * @return Pointer to the raw embedded data structure in the request, ready to be filled out.
*/ */
DEPRECATED
static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) { static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) {
u32* buf = (u32*)armGetTls(); u32* buf = (u32*)armGetTls();
size_t i; size_t i;
@ -350,6 +365,7 @@ static inline void* ipcPrepareHeader(IpcCommand* cmd, size_t sizeof_raw) {
* @param session IPC session handle. * @param session IPC session handle.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcDispatch(Handle session) { static inline Result ipcDispatch(Handle session) {
return svcSendSyncRequest(session); return svcSendSyncRequest(session);
} }
@ -361,8 +377,8 @@ static inline Result ipcDispatch(Handle session) {
/// IPC parsed command (response) structure. /// IPC parsed command (response) structure.
typedef struct { typedef struct {
IpcCommandType CommandType; ///< Type of the command IpcCommandType CommandType; ///< Type of the command
bool HasPid; ///< true if the 'Pid' field is filled out. bool HasPid; ///< true if the 'Pid' field is filled out.
u64 Pid; ///< PID included in the response (only if HasPid is true) u64 Pid; ///< PID included in the response (only if HasPid is true)
@ -376,7 +392,7 @@ typedef struct {
u32 InThisObjectId; ///< Object ID to call the command on (for domain messages). u32 InThisObjectId; ///< Object ID to call the command on (for domain messages).
size_t InNumObjectIds; ///< Number of object IDs (for domain messages). size_t InNumObjectIds; ///< Number of object IDs (for domain messages).
u32 InObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain messages). u32 InObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain messages).
bool IsDomainResponse; ///< true if the the message is a Domain response. bool IsDomainResponse; ///< true if the the message is a Domain response.
size_t OutNumObjectIds; ///< Number of object IDs (for domain responses). size_t OutNumObjectIds; ///< Number of object IDs (for domain responses).
u32 OutObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain responses). u32 OutObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain responses).
@ -391,25 +407,26 @@ typedef struct {
void* Statics[IPC_MAX_BUFFERS]; ///< Pointers to the statics. void* Statics[IPC_MAX_BUFFERS]; ///< Pointers to the statics.
size_t StaticSizes[IPC_MAX_BUFFERS]; ///< Sizes of the statics. size_t StaticSizes[IPC_MAX_BUFFERS]; ///< Sizes of the statics.
u8 StaticIndices[IPC_MAX_BUFFERS]; ///< Indices of the statics. u8 StaticIndices[IPC_MAX_BUFFERS]; ///< Indices of the statics.
size_t NumStaticsOut; ///< Number of output statics available in the response. size_t NumStaticsOut; ///< Number of output statics available in the response.
void* Raw; ///< Pointer to the raw embedded data structure in the response. void* Raw; ///< Pointer to the raw embedded data structure in the response.
void* RawWithoutPadding; ///< Pointer to the raw embedded data structure, without padding. void* RawWithoutPadding; ///< Pointer to the raw embedded data structure, without padding.
size_t RawSize; ///< Size of the raw embedded data. size_t RawSize; ///< Size of the raw embedded data.
} IpcParsedCommand; } IpcParsedCommand DEPRECATED;
/** /**
* @brief Parse an IPC command response into an IPC parsed command structure. * @brief Parse an IPC command response into an IPC parsed command structure.
* @param r IPC parsed command structure to fill in. * @param r IPC parsed command structure to fill in.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcParse(IpcParsedCommand* r) { static inline Result ipcParse(IpcParsedCommand* r) {
u32* buf = (u32*)armGetTls(); u32* buf = (u32*)armGetTls();
u32 ctrl0 = *buf++; u32 ctrl0 = *buf++;
u32 ctrl1 = *buf++; u32 ctrl1 = *buf++;
size_t i; size_t i;
r->IsDomainRequest = false; r->IsDomainRequest = false;
r->IsDomainResponse = false; r->IsDomainResponse = false;
@ -417,7 +434,7 @@ static inline Result ipcParse(IpcParsedCommand* r) {
r->HasPid = false; r->HasPid = false;
r->RawSize = (ctrl1 & 0x1ff) * 4; r->RawSize = (ctrl1 & 0x1ff) * 4;
r->NumHandles = 0; r->NumHandles = 0;
r->NumStaticsOut = (ctrl1 >> 10) & 15; r->NumStaticsOut = (ctrl1 >> 10) & 15;
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 2 -> Single descriptor if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 2 -> Single descriptor
if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 3+ -> (Value - 2) descriptors if (r->NumStaticsOut >> 1) r->NumStaticsOut--; // Value 3+ -> (Value - 2) descriptors
@ -505,6 +522,7 @@ static inline Result ipcParse(IpcParsedCommand* r) {
* @param size Output variable in which to store the size. * @param size Output variable in which to store the size.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) { static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) {
u32* buf = (u32*)armGetTls(); u32* buf = (u32*)armGetTls();
@ -544,6 +562,7 @@ static inline Result ipcQueryPointerBufferSize(Handle session, size_t *size) {
* @param session IPC session handle. * @param session IPC session handle.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcCloseSession(Handle session) { static inline Result ipcCloseSession(Handle session) {
u32* buf = (u32*)armGetTls(); u32* buf = (u32*)armGetTls();
buf[0] = IpcCommandType_Close; buf[0] = IpcCommandType_Close;
@ -558,6 +577,7 @@ static inline Result ipcCloseSession(Handle session) {
* @param new_session_out Output cloned IPC session handle. * @param new_session_out Output cloned IPC session handle.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcCloneSession(Handle session, u32 unk, Handle* new_session_out) { static inline Result ipcCloneSession(Handle session, u32 unk, Handle* new_session_out) {
u32* buf = (u32*)armGetTls(); u32* buf = (u32*)armGetTls();
@ -603,6 +623,7 @@ static inline Result ipcCloneSession(Handle session, u32 unk, Handle* new_sessio
* @param object_id_out Output variable in which to store the object ID. * @param object_id_out Output variable in which to store the object ID.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_out) { static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_out) {
u32* buf = (u32*)armGetTls(); u32* buf = (u32*)armGetTls();
@ -640,6 +661,7 @@ static inline Result ipcConvertSessionToDomain(Handle session, u32* object_id_ou
* @param cmd IPC domain command structure. * @param cmd IPC domain command structure.
* @param object_id Object ID to send. * @param object_id Object ID to send.
*/ */
DEPRECATED
static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) { static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) {
cmd->ObjectIds[cmd->NumObjectIds++] = object_id; cmd->ObjectIds[cmd->NumObjectIds++] = object_id;
} }
@ -651,6 +673,7 @@ static inline void ipcSendObjectId(IpcCommand* cmd, u32 object_id) {
* @param object_id Domain object ID. * @param object_id Domain object ID.
* @return Pointer to the raw embedded data structure in the request, ready to be filled out. * @return Pointer to the raw embedded data structure in the request, ready to be filled out.
*/ */
DEPRECATED
static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw, u32 object_id) { static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw, u32 object_id) {
void* raw = ipcPrepareHeader(cmd, sizeof_raw + sizeof(DomainMessageHeader) + cmd->NumObjectIds*sizeof(u32)); void* raw = ipcPrepareHeader(cmd, sizeof_raw + sizeof(DomainMessageHeader) + cmd->NumObjectIds*sizeof(u32));
DomainMessageHeader* hdr = (DomainMessageHeader*) raw; DomainMessageHeader* hdr = (DomainMessageHeader*) raw;
@ -672,6 +695,7 @@ static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw
* @param r IPC parsed command structure to fill in. * @param r IPC parsed command structure to fill in.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcParseDomainRequest(IpcParsedCommand* r) { static inline Result ipcParseDomainRequest(IpcParsedCommand* r) {
Result rc = ipcParse(r); Result rc = ipcParse(r);
DomainMessageHeader *hdr; DomainMessageHeader *hdr;
@ -710,6 +734,7 @@ static inline Result ipcParseDomainRequest(IpcParsedCommand* r) {
* @param sizeof_raw Size in bytes of the raw data structure. * @param sizeof_raw Size in bytes of the raw data structure.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_raw) { static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_raw) {
Result rc = ipcParse(r); Result rc = ipcParse(r);
DomainResponseHeader *hdr; DomainResponseHeader *hdr;
@ -722,7 +747,7 @@ static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_r
object_ids = (u32*)(((uintptr_t) r->Raw) + sizeof_raw);//Official sw doesn't align this. object_ids = (u32*)(((uintptr_t) r->Raw) + sizeof_raw);//Official sw doesn't align this.
r->IsDomainResponse = true; r->IsDomainResponse = true;
r->OutNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds; r->OutNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
if ((uintptr_t)object_ids + sizeof(u32) * r->OutNumObjectIds - (uintptr_t)armGetTls() >= 0x100) { if ((uintptr_t)object_ids + sizeof(u32) * r->OutNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds); return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
@ -739,6 +764,7 @@ static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_r
* @param object_id ID of the object to close. * @param object_id ID of the object to close.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result ipcCloseObjectById(Handle session, u32 object_id) { static inline Result ipcCloseObjectById(Handle session, u32 object_id) {
IpcCommand c; IpcCommand c;
DomainMessageHeader* hdr; DomainMessageHeader* hdr;
@ -756,3 +782,5 @@ static inline Result ipcCloseObjectById(Handle session, u32 object_id) {
} }
///@} ///@}
#pragma GCC diagnostic pop

View File

@ -123,6 +123,7 @@ enum {
LibnxError_NvinfoFailedToInitialize, LibnxError_NvinfoFailedToInitialize,
LibnxError_NvbufFailedToInitialize, LibnxError_NvbufFailedToInitialize,
LibnxError_LibAppletBadExit, LibnxError_LibAppletBadExit,
LibnxError_InvalidCmifOutHeader,
}; };
/// libnx binder error codes /// libnx binder error codes

View File

@ -49,7 +49,7 @@ int fsdevTranslatePath(const char *path, FsFileSystem** device, char *outpath);
Result fsdevSetArchiveBit(const char *path); Result fsdevSetArchiveBit(const char *path);
/// This calls fsFsCreateFile on the filesystem specified by the input path (as used in stdio). /// This calls fsFsCreateFile on the filesystem specified by the input path (as used in stdio).
Result fsdevCreateFile(const char* path, size_t size, int flags); Result fsdevCreateFile(const char* path, size_t size, u32 flags);
/// Recursively deletes the directory specified by the input path (as used in stdio). /// Recursively deletes the directory specified by the input path (as used in stdio).
Result fsdevDeleteDirectoryRecursively(const char *path); Result fsdevDeleteDirectoryRecursively(const char *path);

View File

@ -6,6 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/acc.h"
/// Structure representing an entry in the homebrew environment configuration. /// Structure representing an entry in the homebrew environment configuration.
typedef struct { typedef struct {
@ -114,4 +115,4 @@ bool envHasRandomSeed(void);
void envGetRandomSeed(u64 out[2]); void envGetRandomSeed(u64 out[2]);
/// Returns a pointer to the user id storage area (if present). /// Returns a pointer to the user id storage area (if present).
u128* envGetUserIdStorage(void); AccountUid* envGetUserIdStorage(void);

View File

@ -6,37 +6,60 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "sm.h" #include "../sf/service.h"
#define ACC_USER_LIST_SIZE 8 #define ACC_USER_LIST_SIZE 8
typedef enum {
AccountServiceType_NotInitialized = 0, ///< Same as ::AccountServiceType_Application during \ref accountInitialize.
AccountServiceType_Application = 1, ///< Initializes acc:u0.
AccountServiceType_System = 2, ///< Initializes acc:u1.
AccountServiceType_Administrator = 3, ///< Initializes acc:su.
} AccountServiceType;
/// Profile /// Profile
typedef struct { typedef struct {
Service s; Service s; ///< IProfile
} AccountProfile; } AccountProfile;
typedef struct /// Account UserId.
{ typedef struct {
u32 unk_x0; u64 uid[2]; ///< UserId. All-zero is invalid / Uid not set. See also \ref accountUidIsValid.
} AccountUid;
/// UserData
typedef struct {
u32 unk_x0; ///< Unknown.
u32 iconID; ///< Icon ID. 0 = Mii, the rest are character icon IDs. u32 iconID; ///< Icon ID. 0 = Mii, the rest are character icon IDs.
u8 iconBackgroundColorID; ///< Profile icon background color ID u8 iconBackgroundColorID; ///< Profile icon background color ID
u8 unk_x9[0x7]; u8 unk_x9[0x7]; ///< Unknown.
u8 miiID[0x10]; ///< Some ID related to the Mii? All zeros when a character icon is used. u8 miiID[0x10]; ///< Some ID related to the Mii? All zeros when a character icon is used.
u8 unk_x20[0x60]; ///< Usually zeros? u8 unk_x20[0x60]; ///< Usually zeros?
} PACKED AccountUserData; } AccountUserData;
typedef struct /// ProfileBase
{ typedef struct {
u128 userID; AccountUid userID; ///< \ref AccountUid
u64 lastEditTimestamp; ///< POSIX UTC timestamp, for the last account edit. u64 lastEditTimestamp; ///< POSIX UTC timestamp, for the last account edit.
char username[0x20]; ///< UTF-8 Username. char nickname[0x20]; ///< UTF-8 Nickname.
} PACKED AccountProfileBase; } AccountProfileBase;
/**
* @brief Sets the \ref AccountServiceType for initialization. Call this function before \ref accountInitialize, if needed.
* @note By default ::AccountServiceType_NotInitialized will be used.
*/
void accountSetServiceType(AccountServiceType serviceType);
/// Initialize account.
Result accountInitialize(void); Result accountInitialize(void);
/// Exit account.
void accountExit(void); void accountExit(void);
/// Gets the Service object for the actual account service session.
Service* accountGetServiceSession(void); Service* accountGetServiceSession(void);
/// Get the total number of user profiles /// Get the total number of user profiles.
Result accountGetUserCount(s32* user_count); Result accountGetUserCount(s32* user_count);
/** /**
@ -45,26 +68,35 @@ Result accountGetUserCount(s32* user_count);
* @param max_userIDs Maximum number of user IDs to return. * @param max_userIDs Maximum number of user IDs to return.
* @param actual_total The actual total number of user IDs found. * @param actual_total The actual total number of user IDs found.
*/ */
Result accountListAllUsers(u128* userIDs, size_t max_userIDs, size_t *actual_total); Result accountListAllUsers(AccountUid* userIDs, s32 max_userIDs, s32 *actual_total);
/// Get the userID for the last opened user. The output userID is only valid when the output account_selected==1. /// Get the userID for the last opened user.
Result accountGetLastOpenedUser(u128 *userID, bool *account_selected); Result accountGetLastOpenedUser(AccountUid *userID);
/// Get an AccountProfile for the specified userID. /// Get an AccountProfile for the specified userID.
Result accountGetProfile(AccountProfile* out, u128 userID); Result accountGetProfile(AccountProfile* out, const AccountUid *userID);
/// Close the AccountProfile.
void accountProfileClose(AccountProfile* profile);
/// Get \ref AccountUserData and \ref AccountProfileBase for the specified profile, userdata is optional (can be NULL). /// Get \ref AccountUserData and \ref AccountProfileBase for the specified profile, userdata is optional (can be NULL).
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase); Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase);
/// Get the icon image size. /// Get the icon image size.
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size); Result accountProfileGetImageSize(AccountProfile* profile, u32* image_size);
/// Load the JPEG profile icon, valid for both Miis and character icons. The output image_size is the same as the one from \ref accountProfileGetImageSize. /// Load the JPEG profile icon, valid for both Miis and character icons. The output image_size is the same as the one from \ref accountProfileGetImageSize.
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size); Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, u32* image_size);
void accountProfileClose(AccountProfile* profile);
/// Gets the userID which was selected by the profile-selector applet (if any), prior to launching the currently running Application title. /// Gets the userID which was selected by the profile-selector applet (if any), prior to launching the currently running Application title.
/// This gets the cached PreselectedUser loaded during accountInitialize, when PreselectedUser is available. /// This gets the cached PreselectedUser loaded during accountInitialize, when PreselectedUser is available.
Result accountGetPreselectedUser(u128 *userID); Result accountGetPreselectedUser(AccountUid *userID);
/**
* @brief Checks whether the specified \ref AccountUid is valid/set (non-zero).
* @param[in] Uid \ref AccountUid
*/
NX_CONSTEXPR bool accountUidIsValid(const AccountUid *Uid) {
return Uid->uid[0]!=0 || Uid->uid[1]!=0;
}

View File

@ -1,12 +1,18 @@
/** /**
* @file apm.h * @file apm.h
* @brief Performance management (apm) service IPC wrapper. This is used internally by applet with __nx_applet_PerformanceConfiguration, however if you prefer non-init/exit can be used manually. * @brief Performance management (apm) service IPC wrapper. This is used internally by applet with __nx_applet_PerformanceConfiguration, however if you prefer non-init/exit can be used manually. See also: https://switchbrew.org/wiki/PTM_services#apm:am
* @author yellows8 * @author yellows8
* @copyright libnx Authors * @copyright libnx Authors
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
/// PerformanceMode
typedef enum {
ApmPerformanceMode_Handheld = 0, ///< Handheld
ApmPerformanceMode_Docked = 1, ///< Docked
} ApmPerformanceMode;
/// CpuBoostMode. With \ref appletSetCpuBoostMode, only values 0/1 are available. This allows using higher clock rates. /// CpuBoostMode. With \ref appletSetCpuBoostMode, only values 0/1 are available. This allows using higher clock rates.
typedef enum { typedef enum {
@ -15,9 +21,28 @@ typedef enum {
ApmCpuBoostMode_Type2 = 2, ///< Use performance configurations 0x9222000B and 0x9222000C. ApmCpuBoostMode_Type2 = 2, ///< Use performance configurations 0x9222000B and 0x9222000C.
} ApmCpuBoostMode; } ApmCpuBoostMode;
/// Initialize apm. Used automatically by \ref appletInitialize.
Result apmInitialize(void); Result apmInitialize(void);
/// Exit apm. Used automatically by \ref appletExit.
void apmExit(void); void apmExit(void);
/// Gets the Service object for the actual apm service session.
Service* apmGetServiceSession(void); Service* apmGetServiceSession(void);
Result apmSetPerformanceConfiguration(u32 PerformanceMode, u32 PerformanceConfiguration); /// Gets the Service object for ISession.
Result apmGetPerformanceConfiguration(u32 PerformanceMode, u32 *PerformanceConfiguration); Service* apmGetServiceSession_Session(void);
/**
* @brief Sets the PerformanceConfiguration for the specified PerformanceMode.
* @param[in] PerformanceMode \ref ApmPerformanceMode
* @param[in] PerformanceConfiguration PerformanceConfiguration
*/
Result apmSetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 PerformanceConfiguration);
/**
* @brief Gets the PerformanceConfiguration for the specified PerformanceMode.
* @param[in] PerformanceMode \ref ApmPerformanceMode
* @param[out] PerformanceConfiguration PerformanceConfiguration
*/
Result apmGetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 *PerformanceConfiguration);

View File

@ -7,12 +7,13 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
#include "../services/apm.h" #include "../services/apm.h"
#include "../services/pdm.h" #include "../services/pdm.h"
#include "../services/caps.h" #include "../services/caps.h"
#include "../services/pm.h" #include "../services/pm.h"
#include "../services/fs.h" #include "../services/fs.h"
#include "../services/acc.h"
#include "../kernel/tmem.h" #include "../kernel/tmem.h"
#include "../kernel/event.h" #include "../kernel/event.h"
#include "../nacp.h" #include "../nacp.h"
@ -740,13 +741,6 @@ Result appletGetCurrentIlluminanceEx(bool *bOverLimit, float *fLux);
*/ */
Result appletSetWirelessPriorityMode(AppletWirelessPriorityMode mode); Result appletSetWirelessPriorityMode(AppletWirelessPriorityMode mode);
/**
* @brief Sets whether ::AppletMessage_AlbumImageTaken is enabled.
* @note Only available with [7.0.0+].
* @param[in] flag Whether to enable the notification.
*/
Result appletSetAlbumImageTakenNotificationEnabled(bool flag);
/** /**
* @brief Gets the total time in nanoseconds that the current process was actively running (not suspended), relative to when \ref appletInitialize was last used. * @brief Gets the total time in nanoseconds that the current process was actively running (not suspended), relative to when \ref appletInitialize was last used.
* @note Only available with [6.0.0+]. * @note Only available with [6.0.0+].
@ -754,6 +748,13 @@ Result appletSetAlbumImageTakenNotificationEnabled(bool flag);
*/ */
Result appletGetProgramTotalActiveTime(u64 *activeTime); Result appletGetProgramTotalActiveTime(u64 *activeTime);
/**
* @brief Sets whether ::AppletMessage_AlbumImageTaken is enabled.
* @note Only available with [7.0.0+].
* @param[in] flag Whether to enable the notification.
*/
Result appletSetAlbumImageTakenNotificationEnabled(bool flag);
/** /**
* @brief Sets the Application AlbumUserData. * @brief Sets the Application AlbumUserData.
* @note Only available with [8.0.0+]. * @note Only available with [8.0.0+].
@ -1423,13 +1424,13 @@ Result appletQueryApplicationPlayStatistics(PdmApplicationPlayStatistics *stats,
/** /**
* @brief Same as \ref appletQueryApplicationPlayStatistics except this gets playstats specific to the input userID. * @brief Same as \ref appletQueryApplicationPlayStatistics except this gets playstats specific to the input userID.
* @note Only available with AppletType_*Application on [6.0.0+]. * @note Only available with AppletType_*Application on [6.0.0+].
* @param userID userID * @param[in] uid \ref AccountUid
* @param stats Output \ref PdmApplicationPlayStatistics array. * @param[out] stats Output \ref PdmApplicationPlayStatistics array.
* @param titleIDs Input titleIDs array. * @param[in] titleIDs Input titleIDs array.
* @param count Total entries in the input/output arrays. * @param[in] count Total entries in the input/output arrays.
* @param total_out Total output entries. * @param[out] total_out Total output entries.
*/ */
Result appletQueryApplicationPlayStatisticsByUid(u128 userID, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out); Result appletQueryApplicationPlayStatisticsByUid(AccountUid *uid, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out);
/** /**
* @brief Launches Application title {current_titleID}+programIndex. This will enter an infinite-sleep-loop on success. * @brief Launches Application title {current_titleID}+programIndex. This will enter an infinite-sleep-loop on success.
@ -1476,6 +1477,14 @@ Result appletGetPreviousProgramIndex(s32 *programIndex);
*/ */
Result appletGetGpuErrorDetectedSystemEvent(Event *out_event); Result appletGetGpuErrorDetectedSystemEvent(Event *out_event);
/**
* @brief CreateMovieMaker. Do not use this directly, use \ref grcCreateMovieMaker instead.
* @note Only available with AppletType_*Application on [5.0.0+].
* @param[out] srv_out Output Service for applet IMovieMaker.
* @param[in] tmem TransferMemory
*/
Result appletCreateMovieMaker(Service* srv_out, TransferMemory *tmem);
/** /**
* @brief Launches the jit-sysmodule when it was not previously launched by this cmd. Returns 0 when it was previously launched. * @brief Launches the jit-sysmodule when it was not previously launched by this cmd. Returns 0 when it was previously launched.
* @note Only available with AppletType_*Application on [5.0.0+]. * @note Only available with AppletType_*Application on [5.0.0+].
@ -1532,12 +1541,12 @@ Result appletGetHomeButtonWriterLockAccessor(AppletLockAccessor *a);
/** /**
* @brief PopRequestLaunchApplicationForDebug * @brief PopRequestLaunchApplicationForDebug
* @note Only available with AppletType_SystemApplet on [6.0.0+]. * @note Only available with AppletType_SystemApplet on [6.0.0+].
* @param[out] userIDs Output array of userIDs. * @param[out] userIDs Output array of \ref AccountUid.
* @param[in] count Size of the userID array in entries, must be at least the size stored in state. * @param[in] count Size of the userID array in entries, must be at least the size stored in state.
* @param[out] titleID Output Application titleID. * @param[out] titleID Output Application titleID.
* @param[out] total_out Total output userID entries. * @param[out] total_out Total output userID entries.
*/ */
Result appletPopRequestLaunchApplicationForDebug(u128 *userIDs, s32 count, u64 *titleID, s32 *total_out); Result appletPopRequestLaunchApplicationForDebug(AccountUid *userIDs, s32 count, u64 *titleID, s32 *total_out);
/** /**
* @brief Launches DevMenu and the dev Overlay-applet. This will enter an infinite-sleep-loop on success. * @brief Launches DevMenu and the dev Overlay-applet. This will enter an infinite-sleep-loop on success.
@ -1774,11 +1783,11 @@ Result appletApplicationGetApplicationLaunchRequestInfo(AppletApplication *a, Ap
* @brief SetUsers for the Application. * @brief SetUsers for the Application.
* @note Only available on [6.0.0+]. * @note Only available on [6.0.0+].
* @param a \ref AppletApplication * @param a \ref AppletApplication
* @param[in] userIDs Input array of userIDs. * @param[in] userIDs Input array of \ref AccountUid.
* @param[in] count Size of the userID array in entries, must be <=ACC_USER_LIST_SIZE. * @param[in] count Size of the userID array in entries, must be <=ACC_USER_LIST_SIZE.
* @param[in] flag When this flag is true, this just clears the users_available state flag to 0 and returns. * @param[in] flag When this flag is true, this just clears the users_available state flag to 0 and returns.
*/ */
Result appletApplicationSetUsers(AppletApplication *a, const u128 *userIDs, s32 count, bool flag); Result appletApplicationSetUsers(AppletApplication *a, const AccountUid *userIDs, s32 count, bool flag);
/** /**
* @brief CheckRightsEnvironmentAvailable. * @brief CheckRightsEnvironmentAvailable.
@ -1801,11 +1810,11 @@ Result appletApplicationGetNsRightsEnvironmentHandle(AppletApplication *a, u64 *
* @note Only available on [6.0.0+]. * @note Only available on [6.0.0+].
* @note qlaunch only uses 1 userID with this. * @note qlaunch only uses 1 userID with this.
* @param a \ref AppletApplication * @param a \ref AppletApplication
* @param[out] userIDs Output array of userIDs. * @param[out] userIDs Output array of \ref AccountUid.
* @param[in] count Size of the userID array in entries, must be at least the size stored in state. * @param[in] count Size of the userID array in entries, must be at least the size stored in state.
* @param[out] total_out Total output entries. * @param[out] total_out Total output entries.
*/ */
Result appletApplicationGetDesirableUids(AppletApplication *a, u128 *userIDs, s32 count, s32 *total_out); Result appletApplicationGetDesirableUids(AppletApplication *a, AccountUid *userIDs, s32 count, s32 *total_out);
/** /**
* @brief ReportApplicationExitTimeout. * @brief ReportApplicationExitTimeout.
@ -2029,12 +2038,12 @@ Result appletUnreserveResourceForMovieOperation(void);
/** /**
* @brief Gets an array of userIDs for the MainApplet AvailableUsers. * @brief Gets an array of userIDs for the MainApplet AvailableUsers.
* @note Only available with AppletType_LibraryApplet on [6.0.0+]. * @note Only available with AppletType_LibraryApplet on [6.0.0+].
* @param[out] userIDs Output array of userIDs. * @param[out] userIDs Output array of \ref AccountUid.
* @param[in] count Size of the userID array in entries, must be at least ACC_USER_LIST_SIZE. * @param[in] count Size of the userID array in entries, must be at least ACC_USER_LIST_SIZE.
* @param[out] flag When true, this indicates that no users are available. * @param[out] flag When true, this indicates that no users are available.
* @param[out] total_out Total output entries. This is -1 when flag is true. * @param[out] total_out Total output entries. This is -1 when flag is true.
*/ */
Result appletGetMainAppletAvailableUsers(u128 *userIDs, s32 count, bool *flag, s32 *total_out); Result appletGetMainAppletAvailableUsers(AccountUid *userIDs, s32 count, bool *flag, s32 *total_out);
///@} ///@}
@ -2129,7 +2138,7 @@ Result appletBeginToObserveHidInputForDevelop(void);
* @param[in] offset Offset within the ThemeStorage. * @param[in] offset Offset within the ThemeStorage.
* @param[out] transfer_size Actual read size. * @param[out] transfer_size Actual read size.
*/ */
Result appletReadThemeStorage(void* buffer, size_t size, u64 offset, size_t *transfer_size); Result appletReadThemeStorage(void* buffer, size_t size, u64 offset, u64 *transfer_size);
/** /**
* @brief Writes the ThemeStorage for the current applet. * @brief Writes the ThemeStorage for the current applet.
@ -2201,13 +2210,13 @@ Result appletInvalidateTransitionLayer(void);
* @brief Requests to launch the specified Application, with the specified users. * @brief Requests to launch the specified Application, with the specified users.
* @note Only available on [6.0.0+]. * @note Only available on [6.0.0+].
* @param[in] titleID Application titleID. * @param[in] titleID Application titleID.
* @param[in] userIDs Input array of userIDs. * @param[in] userIDs Input array of \ref AccountUid.
* @param[in] total_userIDs Total input userIDs, must be <=ACC_USER_LIST_SIZE. * @param[in] total_userIDs Total input userIDs, must be <=ACC_USER_LIST_SIZE.
* @param[in] flag Whether to use the specified buffer to create a storage which will be pushed for ::AppletLaunchParameterKind_UserChannel. * @param[in] flag Whether to use the specified buffer to create a storage which will be pushed for ::AppletLaunchParameterKind_UserChannel.
* @param[in] buffer Buffer containing the above storage data. * @param[in] buffer Buffer containing the above storage data.
* @param[in] size Size of the storage buffer. * @param[in] size Size of the storage buffer.
*/ */
Result appletRequestLaunchApplicationWithUserAndArgumentForDebug(u64 titleID, u128 *userIDs, size_t total_userIDs, bool flag, const void* buffer, size_t size); Result appletRequestLaunchApplicationWithUserAndArgumentForDebug(u64 titleID, AccountUid *userIDs, size_t total_userIDs, bool flag, const void* buffer, size_t size);
/** /**
* @brief Gets the \ref AppletResourceUsageInfo. * @brief Gets the \ref AppletResourceUsageInfo.
@ -2262,8 +2271,8 @@ void appletHook(AppletHookCookie* cookie, AppletHookFn callback, void* param);
void appletUnhook(AppletHookCookie* cookie); void appletUnhook(AppletHookCookie* cookie);
/// These return state which is updated by appletMainLoop() when notifications are received. /// These return state which is updated by appletMainLoop() when notifications are received.
u8 appletGetOperationMode(void); AppletOperationMode appletGetOperationMode(void);
u32 appletGetPerformanceMode(void); ApmPerformanceMode appletGetPerformanceMode(void);
AppletFocusState appletGetFocusState(void); AppletFocusState appletGetFocusState(void);
Result appletSetFocusHandlingMode(AppletFocusHandlingMode mode); Result appletSetFocusHandlingMode(AppletFocusHandlingMode mode);

View File

@ -0,0 +1,113 @@
/**
* @file async.h
* @brief NS/NIM IAsync* IPC wrapper.
* @author yellows8
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
#include "../applets/error.h"
#include "../kernel/event.h"
/// AsyncValue
typedef struct {
Service s; ///< IAsyncValue
Event event; ///< Event with autoclear=false.
} AsyncValue;
/// AsyncResult
typedef struct {
Service s; ///< IAsyncResult
Event event; ///< Event with autoclear=false.
} AsyncResult;
///@name IAsyncValue
///@{
/**
* @brief Close a \ref AsyncValue.
* @note When the object is initialized, this uses \ref asyncValueCancel then \ref asyncValueWait with timeout=U64_MAX.
* @param a \ref AsyncValue
*/
void asyncValueClose(AsyncValue *a);
/**
* @brief Waits for the async operation to finish using the specified timeout.
* @param a \ref AsyncValue
* @param[in] timeout Timeout in nanoseconds. U64_MAX for no timeout.
*/
Result asyncValueWait(AsyncValue *a, u64 timeout);
/**
* @brief Gets the value size.
* @param a \ref AsyncValue
* @param[out] size Output size.
*/
Result asyncValueGetSize(AsyncValue *a, u64 *size);
/**
* @brief Gets the value.
* @note Prior to using the cmd, this uses \ref asyncResultWait with timeout=U64_MAX.
* @param a \ref AsyncValue
* @param[out] buffer Output buffer.
* @param[in] size Output buffer size.
*/
Result asyncValueGet(AsyncValue *a, void* buffer, size_t size);
/**
* @brief Cancels the async operation.
* @note Used automatically by \ref asyncValueClose.
* @param a \ref AsyncValue
*/
Result asyncValueCancel(AsyncValue *a);
/**
* @brief Gets the \ref ErrorContext.
* @param a \ref AsyncValue
* @param[out] context \ref ErrorContext
*/
Result asyncValueGetErrorContext(AsyncValue *a, ErrorContext *context);
///@}
///@name IAsyncResult
///@{
/**
* @brief Close a \ref AsyncResult.
* @note When the object is initialized, this uses \ref asyncResultCancel then \ref asyncResultWait with timeout=U64_MAX.
* @param a \ref AsyncResult
*/
void asyncResultClose(AsyncResult *a);
/**
* @brief Waits for the async operation to finish using the specified timeout.
* @param a \ref AsyncResult
* @param[in] timeout Timeout in nanoseconds. U64_MAX for no timeout.
*/
Result asyncResultWait(AsyncResult *a, u64 timeout);
/**
* @brief Gets the Result.
* @note Prior to using the cmd, this uses \ref asyncResultWait with timeout=U64_MAX.
* @param a \ref AsyncResult
*/
Result asyncResultGet(AsyncResult *a);
/**
* @brief Cancels the async operation.
* @note Used automatically by \ref asyncResultClose.
* @param a \ref AsyncResult
*/
Result asyncResultCancel(AsyncResult *a);
/**
* @brief Gets the \ref ErrorContext.
* @param a \ref AsyncResult
* @param[out] context \ref ErrorContext
*/
Result asyncResultGetErrorContext(AsyncResult *a, ErrorContext *context);
///@}

View File

@ -9,12 +9,6 @@
#include "../audio/audio.h" #include "../audio/audio.h"
#include "../services/sm.h" #include "../services/sm.h"
#if __cplusplus >= 201402L
#define AUDREN_CONSTEXPR constexpr
#else
#define AUDREN_CONSTEXPR static inline
#endif
#define AUDREN_TIMER_FREQ_HZ 200.0f #define AUDREN_TIMER_FREQ_HZ 200.0f
#define AUDREN_TIMER_PERIOD_MS 5.0f #define AUDREN_TIMER_PERIOD_MS 5.0f
#define AUDREN_SAMPLES_PER_FRAME_32KHZ 160 #define AUDREN_SAMPLES_PER_FRAME_32KHZ 160
@ -287,12 +281,12 @@ static inline u32 audrenGetRevision(void)
return g_audrenRevision; return g_audrenRevision;
} }
AUDREN_CONSTEXPR int audrenGetMemPoolCount(const AudioRendererConfig* config) NX_CONSTEXPR int audrenGetMemPoolCount(const AudioRendererConfig* config)
{ {
return config->num_effects + 4 * config->num_voices; return config->num_effects + 4 * config->num_voices;
} }
AUDREN_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* config) NX_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* config)
{ {
size_t size = 0; size_t size = 0;
size += sizeof(AudioRendererUpdateDataHeader); size += sizeof(AudioRendererUpdateDataHeader);
@ -307,7 +301,7 @@ AUDREN_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* confi
return size; return size;
} }
AUDREN_CONSTEXPR size_t audrenGetOutputParamSize(const AudioRendererConfig* config) NX_CONSTEXPR size_t audrenGetOutputParamSize(const AudioRendererConfig* config)
{ {
size_t size = 0; size_t size = 0;
size += sizeof(AudioRendererUpdateDataHeader); size += sizeof(AudioRendererUpdateDataHeader);

View File

@ -7,21 +7,72 @@
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../services/sm.h"
#include "../services/acc.h"
/// ImageOrientation
typedef enum {
AlbumImageOrientation_Unknown0 = 0, ///< Unknown. Default.
AlbumImageOrientation_Unknown1 = 1, ///< Unknown.
AlbumImageOrientation_Unknown2 = 2, ///< Unknown.
AlbumImageOrientation_Unknown3 = 3, ///< Unknown.
} AlbumImageOrientation;
/// AlbumReportOption
typedef enum {
AlbumReportOption_Disable = 0, ///< Don't display the screenshot-taken Overlay-applet notification.
AlbumReportOption_Enable = 1, ///< Display the screenshot-taken Overlay notification.
} AlbumReportOption;
/// ContentType
typedef enum {
CapsContentType_Screenshot = 0, ///< Album screenshots.
CapsContentType_Movie = 1, ///< Album videos.
CapsContentType_ExtraMovie = 3, ///< Videos recorded by the current Application host title via \ref grcCreateMovieMaker.
} CapsContentType;
/// ScreenShotAttribute
typedef struct { typedef struct {
u32 unk_x0; u32 unk_x0; ///< Always set to 0 by official sw.
u8 unk_x4[0x3c]; u32 orientation; ///< \ref AlbumImageOrientation
u32 unk_x8; ///< Always set to 0 by official sw.
u32 unk_xc; ///< Always set to 1 by official sw.
u8 unk_x10[0x30]; ///< Always set to 0 by official sw.
} CapsScreenShotAttribute; } CapsScreenShotAttribute;
/// AlbumFileDateTime. This corresponds to each field in the Album entry filename, prior to the "-". /// ScreenShotAttributeForApplication. Only unk_x0 is used by official sw.
typedef struct {
u32 unk_x0; ///< Unknown.
u8 unk_x4; ///< Unknown.
u8 unk_x5; ///< Unknown.
u8 unk_x6; ///< Unknown.
u8 pad; ///< Padding.
u32 unk_x8; ///< Unknown.
u32 unk_xc; ///< Unknown.
u32 unk_x10; ///< Unknown.
u32 unk_x14; ///< Unknown.
u32 unk_x18; ///< Unknown.
u32 unk_x1c; ///< Unknown.
u16 unk_x20; ///< Unknown.
u16 unk_x22; ///< Unknown.
u16 unk_x24; ///< Unknown.
u16 unk_x26; ///< Unknown.
u8 reserved[0x18]; ///< Always zero.
} CapsScreenShotAttributeForApplication;
/// ScreenShotDecodeOption
typedef struct {
u8 unk_x0[0x20]; ///< Unknown. Set to all-zero by official sw.
} CapsScreenShotDecodeOption;
/// AlbumFileDateTime. This corresponds to each field in the Album entry filename, prior to the "-": "YYYYMMDDHHMMSSII".
typedef struct { typedef struct {
u16 year; ///< Year. u16 year; ///< Year.
u8 month; ///< Month. u8 month; ///< Month.
u8 day; ///< Day. u8 day; ///< Day of the month.
u8 hour; ///< Hour. u8 hour; ///< Hour.
u8 minute; ///< Minute. u8 minute; ///< Minute.
u8 second; ///< Second. u8 second; ///< Second.
u8 unk_x7; ///< Unknown. u8 id; ///< Unique ID for when there's multiple Album files with the same timestamp.
} CapsAlbumFileDateTime; } CapsAlbumFileDateTime;
/// AlbumEntryId /// AlbumEntryId
@ -35,20 +86,79 @@ typedef struct {
/// AlbumEntry /// AlbumEntry
typedef struct { typedef struct {
u8 unk_x0[0x8]; u8 unk_x0[0x8]; ///< Unknown.
CapsAlbumEntryId id; CapsAlbumEntryId id; ///< \ref CapsAlbumEntryId
} CapsAlbumEntry; } CapsAlbumEntry;
/// ApplicationAlbumEntry /// ApplicationAlbumEntry
typedef struct { typedef struct {
u8 unk_x0[0x20]; union {
u8 data[0x20]; ///< Data.
struct {
u8 unk_x0[0x20]; ///< Unknown.
} v0; ///< Pre-7.0.0
struct {
u8 unk_x0[0x8]; ///< Unknown.
u8 unk_x8[0x8]; ///< Unknown.
CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime
u8 unk_x18[0x8]; ///< Unknown.
} v1; ///< [7.0.0+]
};
} CapsApplicationAlbumEntry; } CapsApplicationAlbumEntry;
/// ImageOrientation /// ApplicationAlbumFileEntry
typedef enum { typedef struct {
AlbumImageOrientation_Unknown0 = 0, ///< Unknown. CapsApplicationAlbumEntry entry; ///< \ref CapsApplicationAlbumEntry
AlbumImageOrientation_Unknown1 = 1, ///< Unknown. CapsAlbumFileDateTime datetime; ///< \ref CapsAlbumFileDateTime
AlbumImageOrientation_Unknown2 = 2, ///< Unknown. u64 unk_x28; ///< Unknown.
AlbumImageOrientation_Unknown3 = 3, ///< Unknown. } CapsApplicationAlbumFileEntry;
} AlbumImageOrientation;
/// ApplicationData
typedef struct {
u8 userdata[0x400]; ///< UserData.
u32 size; ///< UserData size.
} CapsApplicationData;
/// UserIdList
typedef struct {
AccountUid userIDs[ACC_USER_LIST_SIZE]; ///< \ref AccountUid
u8 count; ///< Total userIDs.
u8 pad[7]; ///< Padding.
} CapsUserIdList;
/// LoadAlbumScreenShotImageOutputForApplication
typedef struct {
s64 width; ///< Width. Official sw copies this to a s32 output field.
s64 height; ///< Height. Official sw copies this to a s32 output field.
CapsScreenShotAttributeForApplication attr; ///< \ref CapsScreenShotAttributeForApplication
CapsApplicationData appdata; ///< \ref CapsApplicationData
u8 reserved[0xac]; ///< Unused.
} CapsLoadAlbumScreenShotImageOutputForApplication;
/// Gets the ShimLibraryVersion.
u64 capsGetShimLibraryVersion(void);
/// Gets the default start_datetime.
static inline CapsAlbumFileDateTime capsGetDefaultStartDateTime(void) {
return (CapsAlbumFileDateTime){.year = 1970, .month = 1, .day = 1};
}
/// Gets the default end_datetime.
static inline CapsAlbumFileDateTime capsGetDefaultEndDateTime(void) {
return (CapsAlbumFileDateTime){.year = 3000, .month = 1, .day = 1};
}
/// Convert a \ref CapsApplicationAlbumFileEntry to \ref CapsApplicationAlbumEntry.
static inline void capsConvertApplicationAlbumFileEntryToApplicationAlbumEntry(CapsApplicationAlbumEntry *out, CapsApplicationAlbumFileEntry *in) {
*out = in->entry;
}
/// Convert a \ref CapsApplicationAlbumEntry to \ref CapsApplicationAlbumFileEntry. Should only be used on [7.0.0+].
static inline void capsConvertApplicationAlbumEntryToApplicationAlbumFileEntry(CapsApplicationAlbumFileEntry *out, CapsApplicationAlbumEntry *in) {
out->entry = *in;
out->datetime = in->v1.datetime;
out->unk_x28 = 0;
}

View File

@ -6,12 +6,16 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
#include "../services/caps.h" #include "../services/caps.h"
/// Initialize caps:sc. Only available on [2.0.0+]. /// Initialize caps:sc. Only available on [2.0.0+].
Result capsscInitialize(void); Result capsscInitialize(void);
/// Exit caps:sc.
void capsscExit(void); void capsscExit(void);
/// Gets the Service for caps:sc.
Service* capsscGetServiceSession(void); Service* capsscGetServiceSession(void);
/** /**
@ -27,5 +31,5 @@ Service* capsscGetServiceSession(void);
* @param buffer_index Starting image buffer index. Must be < buffer_count. * @param buffer_index Starting image buffer index. Must be < buffer_count.
* @param timeout Timeout in nanoseconds. A default value of 100000000 can be used. * @param timeout Timeout in nanoseconds. A default value of 100000000 can be used.
*/ */
Result capsscCaptureScreenshot(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout); Result capsscCaptureRawImageWithTimeout(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout);

View File

@ -6,17 +6,89 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
#include "../services/acc.h"
#include "../services/caps.h" #include "../services/caps.h"
/// Initialize caps:su. Only available on [4.0.0+]. /// Initialize caps:su. Only available on [4.0.0+].
Result capssuInitialize(void); Result capssuInitialize(void);
/// Exit caps:su.
void capssuExit(void); void capssuExit(void);
/// Gets the Service for caps:su.
Service* capssuGetServiceSession(void); Service* capssuGetServiceSession(void);
/// Same as \ref capssuSaveScreenShotEx0, except this uses an all-zero CapsScreenShotAttribute where the first u32 is set to attr_val. attr_val can be zero. /**
Result capssuSaveScreenShot(const void* buffer, size_t size, u32 unk, u32 attr_val, CapsApplicationAlbumEntry *out); * @brief This is a wrapper for \ref capssuSaveScreenShotEx0.
* @note This uses an all-zero \ref CapsScreenShotAttribute with orientation = input orientation, and unk_xc = 1.
* @param[in] buffer RGBA8 1280x720 image buffer.
* @param[in] size Size of the buffer.
* @param[in] reportoption \ref AlbumReportOption
* @param[in] orientation \ref AlbumImageOrientation
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShot(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, CapsApplicationAlbumEntry *out);
/// Saves an Album screenshot using the specified gfx data in buffer (1280x720 RGBA8), size must be at least 0x384000. unk can be zero. /**
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out); * @brief Similar to \ref capssuSaveScreenShot, except this is a wrapper for \ref capssuSaveScreenShotEx1.
* @note This uses an all-zero \ref CapsScreenShotAttribute with orientation = input orientation, and unk_xc = 1.
* @note Only available on [8.0.0+].
* @param[in] buffer RGBA8 1280x720 image data buffer.
* @param[in] size Size of the buffer.
* @param[in] reportoption \ref AlbumReportOption
* @param[in] orientation \ref AlbumImageOrientation
* @param[in] userdata Input UserData buffer. If NULL, the \ref CapsApplicationData will be empty.
* @param[in] userdata_size Input UserData size, must be within bounds for CapsApplicationData::userdata. If 0, the \ref CapsApplicationData will be empty.
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShotWithUserData(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const void* userdata, size_t userdata_size, CapsApplicationAlbumEntry *out);
/**
* @brief Similar to \ref capssuSaveScreenShot, except this is a wrapper for \ref capssuSaveScreenShotEx2.
* @note This uses an all-zero \ref CapsScreenShotAttribute with orientation = input orientation, and unk_xc = 1.
* @note Only available on [6.0.0+].
* @param[in] buffer RGBA8 1280x720 image data buffer.
* @param[in] size Size of the buffer.
* @param[in] reportoption \ref AlbumReportOption
* @param[in] orientation \ref AlbumImageOrientation
* @param[in] userIDs Input array of \ref AccountUid. If NULL, the \ref CapsUserIdList will be empty.
* @param[in] userID_count Size of the userID array in entries, must be within bounds for CapsUserIdList::userIDs. If 0, the \ref CapsUserIdList will be empty.
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShotWithUserIds(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const AccountUid* userIDs, size_t userID_count, CapsApplicationAlbumEntry *out);
/**
* @brief Saves an Album screenshot using the specified gfx data in the buffer, with the specified \ref CapsScreenShotAttribute.
* @param[in] buffer RGBA8 1280x720 image data buffer.
* @param[in] size Size of the buffer, must be at least 0x384000.
* @param[in] attr \ref CapsScreenShotAttribute
* @param[in] reportoption \ref AlbumReportOption
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out);
/**
* @brief Same as \ref capssuSaveScreenShotEx0, except this allows specifying the \ref CapsApplicationData.
* @note Only available on [8.0.0+].
* @param[in] buffer RGBA8 1280x720 image data buffer.
* @param[in] size Size of the buffer, must be at least 0x384000.
* @param[in] attr \ref CapsScreenShotAttribute
* @param[in] reportoption \ref AlbumReportOption
* @param[in] appdata \ref CapsApplicationData
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShotEx1(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationData *appdata, CapsApplicationAlbumEntry *out);
/**
* @brief Same as \ref capssuSaveScreenShotEx0, except this allows specifying the \ref CapsUserIdList.
* @note Only available on [6.0.0+].
* @param[in] buffer RGBA8 1280x720 image data buffer.
* @param[in] size Size of the buffer, must be at least 0x384000.
* @param[in] attr \ref CapsScreenShotAttribute
* @param[in] reportoption \ref AlbumReportOption
* @param[in] list \ref CapsUserIdList
* @param[out] out \ref CapsApplicationAlbumEntry. Optional, can be NULL.
*/
Result capssuSaveScreenShotEx2(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsUserIdList *list, CapsApplicationAlbumEntry *out);

View File

@ -0,0 +1,173 @@
/**
* @file capsu.h
* @brief Application Album (caps:u) service IPC wrapper.
* This is only usable with AlbumFiles associated with the current Application host title.
* @author yellows8
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
#include "../services/caps.h"
#include "../services/acc.h"
/// Initialize caps:u. Only available on [5.0.0+].
Result capsuInitialize(void);
/// Exit caps:u.
void capsuExit(void);
/// Gets the Service for caps:u.
Service* capsuGetServiceSession(void);
/// Gets the Service for IAlbumAccessorApplicationSession, only initialized after \ref capsuOpenAlbumMovieStream was used (unaffected by using \ref capsuCloseAlbumMovieStream).
Service* capsuGetServiceSession_Accessor(void);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumFileEntry.
* @note On [6.0.0+] this uses GetAlbumFileList1AafeAruidDeprecated, otherwise this uses GetAlbumFileList0AafeAruidDeprecated.
* @note This is an old version of \ref capsuGetAlbumFileList3.
* @param[out] entries Output array of \ref CapsApplicationAlbumFileEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileListDeprecated1(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumFileEntry, where the AlbumFile has an UserId which matches the input one. See also \ref capssuSaveScreenShotWithUserIds.
* @note Only available on [6.0.0+].
* @note This is an old version of \ref capsuGetAlbumFileList4.
* @param[out] entries Output array of \ref CapsApplicationAlbumFileEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] userID \ref AccountUid
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileListDeprecated2(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumEntry.
* @note Only available on [7.0.0+], on prior sysvers use \ref capsuGetAlbumFileListDeprecated1 instead.
* @param[out] entries Output array of \ref CapsApplicationAlbumEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileList3(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries);
/**
* @brief Gets a listing of \ref CapsApplicationAlbumEntry, where the AlbumFile has an UserId which matches the input one. See also \ref capssuSaveScreenShotWithUserIds.
* @note Only available on [7.0.0+], on prior sysvers use \ref capsuGetAlbumFileListDeprecated2 instead.
* @param[out] entries Output array of \ref CapsApplicationAlbumEntry.
* @param[in] count Max size of the output array in entries.
* @param[in] type \ref CapsContentType
* @param[in] start_datetime Start \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] end_datetime End \ref CapsAlbumFileDateTime, when NULL the default is used.
* @param[in] userID \ref AccountUid
* @param[out] total_entries Total output entries.
*/
Result capsuGetAlbumFileList4(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries);
/**
* @brief Deletes the specified AlbumFile.
* @param[in] type \ref CapsContentType, must match ::CapsContentType_ExtraMovie.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
*/
Result capsuDeleteAlbumFile(CapsContentType type, const CapsApplicationAlbumFileEntry *entry);
/**
* @brief Gets the filesize for the entire specified AlbumFile.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
* @param[out] size Output filesize.
*/
Result capsuGetAlbumFileSize(const CapsApplicationAlbumFileEntry *entry, u64 *size);
/**
* @brief Load the ScreenShotImage for the specified AlbumFile.
* @param[out] width Output image width. Optional, can be NULL.
* @param[out] height Output image height. Optional, can be NULL.
* @param[out] attr \ref CapsScreenShotAttributeForApplication
* @param[out] userdata Output buffer containing the UserData. Optional, can be NULL. This buffer is cleared to 0 using userdata_maxsize, prior to doing the memcpy.
* @param[in] userdata_maxsize Max size of the userdata buffer. Optional, can be 0.
* @param[out] userdata_size Userdata size field, clamped to max size sizeof(CapsApplicationData::userdata) when needed.
* @param[out] image RGBA8 image output buffer.
* @param[out] image_size Image buffer size, should be at least large enough for RGBA8 1280x720.
* @param[out] workbuf Work buffer, cleared to 0 by the cmd before it returns.
* @param[out] workbuf_size Work buffer size, must be at least the size of the JPEG within the AlbumFile.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
* @param[in] option \ref CapsScreenShotDecodeOption
*/
Result capsuLoadAlbumScreenShotImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option);
/**
* @brief Load the ScreenShotThumbnailImage for the specified AlbumFile.
* @param[out] width Output image width. Optional, can be NULL.
* @param[out] height Output image height. Optional, can be NULL.
* @param[out] attr \ref CapsScreenShotAttributeForApplication
* @param[out] userdata Output buffer containing the UserData. Optional, can be NULL. This buffer is cleared to 0 using userdata_maxsize, prior to doing the memcpy.
* @param[in] userdata_maxsize Max size of the userdata buffer. Optional, can be 0.
* @param[out] userdata_size Userdata size field, clamped to max size sizeof(CapsApplicationData::userdata) when needed.
* @param[out] image RGBA8 image output buffer.
* @param[out] image_size Image buffer size, should be at least large enough for RGBA8 320x180.
* @param[out] workbuf Work buffer, cleared to 0 by the cmd before it returns.
* @param[out] workbuf_size Work buffer size, must be at least the size of the JPEG within the AlbumFile.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
* @param[in] option \ref CapsScreenShotDecodeOption
*/
Result capsuLoadAlbumScreenShotThumbnailImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option);
/**
* @brief PrecheckToCreateContents. Official sw only uses this with ::CapsContentType_ExtraMovie.
* @param[in] type \ref CapsContentType
* @param[in] unk Unknown.
*/
Result capsuPrecheckToCreateContents(CapsContentType type, u64 unk);
/**
* @brief Opens an AlbumMovieStream.
* @note This opens IAlbumAccessorApplicationSession if not previously opened, it's closed during \ref capsuExit.
* @note Up to 4 streams can be open at the same time. Multiple streams can be open at the same time for the same \ref CapsApplicationAlbumFileEntry.
* @param[out] stream Stream handle.
* @param[in] entry \ref CapsApplicationAlbumFileEntry
*/
Result capsuOpenAlbumMovieStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry);
/**
* @brief Closes an AlbumMovieStream.
* @param[in] stream Stream handle.
*/
Result capsuCloseAlbumMovieStream(u64 stream);
/**
* @brief Gets the data size of an AlbumMovieStream.
* @param[in] stream Stream handle.
* @param[out] size Size of the actual MP4, without the JPEG at the end.
*/
Result capsuGetAlbumMovieStreamSize(u64 stream, u64 *size);
/**
* @brief Reads data from an AlbumMovieStream.
* @note offset(+size) must not be negative. offset and size must be aligned to 0x40000-bytes.
* @note When offset(+size) goes beyond the size from \ref capsuGetAlbumMovieStreamSize, the regions of the buffer which goes beyond that are cleared to 0, and actual_size is still set to the input size.
* @param[in] stream Stream handle.
* @param[in] offset Offset.
* @param[out] Output data buffer.
* @param[in] size Data buffer size.
* @param[out] actual_size Actual read size.
*/
Result capsuReadAlbumMovieStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size);
/**
* @brief Gets the BrokenReason for an AlbumMovieStream.
* @note Official sw doesn't use this.
* @param[in] stream Stream handle.
*/
Result capsuGetAlbumMovieStreamBrokenReason(u64 stream);

View File

@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
Result csrngInitialize(void); Result csrngInitialize(void);
void csrngExit(void); void csrngExit(void);

View File

@ -0,0 +1,16 @@
/**
* @file friend.h
* @brief Friends (friend:*) service IPC wrapper.
* @author yellows8
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../services/sm.h"
/// InAppScreenName
typedef struct {
char name[0x40]; ///< UTF-8 string, NUL-terminated.
u64 languageCode; ///< LanguageCode, see set.h.
} FriendsInAppScreenName;

View File

@ -8,7 +8,9 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../kernel/event.h"
#include "../services/acc.h"
#include "../sf/service.h"
// We use wrapped handles for type safety. // We use wrapped handles for type safety.
@ -17,9 +19,6 @@
/// For use with FsSave. /// For use with FsSave.
#define FS_SAVEDATA_CURRENT_TITLEID 0 #define FS_SAVEDATA_CURRENT_TITLEID 0
/// For use with \ref FsSave and \ref FsSaveDataInfo.
#define FS_SAVEDATA_USERID_COMMONSAVE 0
typedef struct { typedef struct {
u8 c[0x10]; u8 c[0x10];
} FsRightsId; } FsRightsId;
@ -57,7 +56,7 @@ typedef struct
{ {
char name[FS_MAX_PATH]; ///< Entry name. char name[FS_MAX_PATH]; ///< Entry name.
u8 pad[3]; u8 pad[3];
s8 type; ///< See FsEntryType. s8 type; ///< See FsDirEntryType.
u8 pad2[3]; ///< ? u8 pad2[3]; ///< ?
u64 fileSize; ///< File size. u64 fileSize; ///< File size.
} FsDirectoryEntry; } FsDirectoryEntry;
@ -66,7 +65,7 @@ typedef struct
typedef struct typedef struct
{ {
u64 titleID; ///< titleID of the savedata to access when accessing other titles' savedata via SaveData, otherwise FS_SAVEDATA_CURRENT_TITLEID. u64 titleID; ///< titleID of the savedata to access when accessing other titles' savedata via SaveData, otherwise FS_SAVEDATA_CURRENT_TITLEID.
union { u128 userID; } PACKED; ///< userID of the user-specific savedata to access, otherwise FS_SAVEDATA_USERID_COMMONSAVE. See account.h. AccountUid userID; ///< \ref AccountUid for the user-specific savedata to access, otherwise 0 for common savedata.
u64 saveID; ///< saveID, 0 for SaveData. u64 saveID; ///< saveID, 0 for SaveData.
u8 saveDataType; ///< See \ref FsSaveDataType. u8 saveDataType; ///< See \ref FsSaveDataType.
u8 rank; ///< Save data 'rank' or 'precedence'. 0 if this save data is considered the primary save data. 1 if it's considered the secondary save data. u8 rank; ///< Save data 'rank' or 'precedence'. 0 if this save data is considered the primary save data. 1 if it's considered the secondary save data.
@ -108,7 +107,7 @@ typedef struct
u8 saveDataSpaceId; ///< See \ref FsSaveDataSpaceId. u8 saveDataSpaceId; ///< See \ref FsSaveDataSpaceId.
u8 saveDataType; ///< See \ref FsSaveDataType. u8 saveDataType; ///< See \ref FsSaveDataType.
u8 pad[6]; ///< Padding. u8 pad[6]; ///< Padding.
u128 userID; ///< See userID for \ref FsSave. AccountUid userID; ///< FsSave::userID
u64 saveID; ///< See saveID for \ref FsSave. u64 saveID; ///< See saveID for \ref FsSave.
u64 titleID; ///< titleID for FsSaveDataType_SaveData. u64 titleID; ///< titleID for FsSaveDataType_SaveData.
u64 size; ///< Raw saveimage size. u64 size; ///< Raw saveimage size.
@ -126,57 +125,62 @@ typedef struct
u8 padding[7]; u8 padding[7];
} FsTimeStampRaw; } FsTimeStampRaw;
/// Returned by fsFsGetEntryType.
typedef enum { typedef enum {
ENTRYTYPE_DIR = 0, FsDirEntryType_Dir = 0, ///< Entry is a directory.
ENTRYTYPE_FILE = 1, FsDirEntryType_File = 1, ///< Entry is a file.
} FsEntryType; } FsDirEntryType;
/// For use with fsFsOpenFile.
typedef enum typedef enum
{ {
FS_OPEN_READ = BIT(0), ///< Open for reading. FsOpenMode_Read = BIT(0), ///< Open for reading.
FS_OPEN_WRITE = BIT(1), ///< Open for writing. FsOpenMode_Write = BIT(1), ///< Open for writing.
FS_OPEN_APPEND = BIT(2), ///< Append file. FsOpenMode_Append = BIT(2), ///< Append file.
} FsFileFlags; } FsOpenMode;
/// For use with fsFsCreateFile.
typedef enum typedef enum
{ {
FS_CREATE_BIG_FILE = BIT(0), ///< Creates a ConcatenationFile (dir with archive bit) instead of file. FsCreateOption_BigFile = BIT(0), ///< Creates a ConcatenationFile (dir with archive bit) instead of file.
} FsFileCreateFlags; } FsCreateOption;
/// For use with fsFsOpenDirectory. /// For use with fsFsOpenDirectory.
typedef enum typedef enum
{ {
FS_DIROPEN_DIRECTORY = BIT(0), ///< Enable reading directory entries. FsDirOpenMode_ReadDirs = BIT(0), ///< Enable reading directory entries.
FS_DIROPEN_FILE = BIT(1), ///< Enable reading file entries. FsDirOpenMode_ReadFiles = BIT(1), ///< Enable reading file entries.
FS_DIROPEN_NO_FILE_SIZE = BIT(31), ///< Causes result entries to not contain filesize information (always 0). FsDirOpenMode_NoFileSize = BIT(31), ///< Causes result entries to not contain filesize information (always 0).
} FsDirectoryFlags; } FsDirOpenMode;
/// For use with fsFileRead.
typedef enum typedef enum
{ {
FS_READOPTION_NONE = 0, ///< No Option. FsReadOption_None = 0, ///< No option.
} FsReadOption; } FsReadOption;
/// For use with fsFileWrite.
typedef enum typedef enum
{ {
FS_WRITEOPTION_NONE = 0, ///< No option. FsWriteOption_None = 0, ///< No option.
FS_WRITEOPTION_FLUSH = BIT(0), ///< Forces a flush after write. FsWriteOption_Flush = BIT(0), ///< Forces a flush after write.
} FsWriteOption; } FsWriteOption;
typedef enum /// StorageId
{ typedef enum {
FsStorageId_None = 0, FsStorageId_None = 0, ///< None
FsStorageId_Host = 1, FsStorageId_Host = 1, ///< Host
FsStorageId_GameCard = 2, FsStorageId_GameCard = 2, ///< GameCard
FsStorageId_NandSystem = 3, FsStorageId_NandSystem = 3, ///< NandSystem
FsStorageId_NandUser = 4, FsStorageId_NandUser = 4, ///< NandUser
FsStorageId_SdCard = 5, FsStorageId_SdCard = 5, ///< SdCard
} FsStorageId; } FsStorageId;
typedef enum typedef enum
{ {
FS_CONTENTSTORAGEID_NandSystem = 0, FsContentStorageId_NandSystem = 0,
FS_CONTENTSTORAGEID_NandUser = 1, FsContentStorageId_NandUser = 1,
FS_CONTENTSTORAGEID_SdCard = 2, FsContentStorageId_SdCard = 2,
} FsContentStorageId; } FsContentStorageId;
typedef enum typedef enum
@ -213,9 +217,9 @@ typedef enum {
} FsSaveDataFlags; } FsSaveDataFlags;
typedef enum { typedef enum {
FsGameCardAttribute_AutoBoot = (1 << 0), ///< Causes the cartridge to automatically start on bootup FsGameCardAttribute_AutoBoot = BIT(0), ///< Causes the cartridge to automatically start on bootup
FsGameCardAttribute_ForceError = (1 << 1), ///< Causes NS to throw an error on attempt to load the cartridge FsGameCardAttribute_ForceError = BIT(1), ///< Causes NS to throw an error on attempt to load the cartridge
FsGameCardAttribute_Repair = (1 << 2), ///< Indicates that this gamecard is a repair tool. FsGameCardAttribute_Repair = BIT(2), ///< Indicates that this gamecard is a repair tool.
} FsGameCardAttribute; } FsGameCardAttribute;
typedef enum { typedef enum {
@ -262,11 +266,20 @@ typedef enum {
FsBisStorageId_SystemProperPartition = 33, FsBisStorageId_SystemProperPartition = 33,
} FsBisStorageId; } FsBisStorageId;
typedef enum {
FsPriority_Normal = 0,
FsPriority_Realtime = 1,
FsPriority_Low = 2,
FsPriority_Background = 3,
} FsPriority;
Result fsInitialize(void); Result fsInitialize(void);
void fsExit(void); void fsExit(void);
Service* fsGetServiceSession(void); Service* fsGetServiceSession(void);
void fsSetPriority(FsPriority prio);
Result fsOpenBisStorage(FsStorage* out, FsBisStorageId partitionId); Result fsOpenBisStorage(FsStorage* out, FsBisStorageId partitionId);
Result fsOpenBisFileSystem(FsFileSystem* out, FsBisStorageId partitionId, const char* string); Result fsOpenBisFileSystem(FsFileSystem* out, FsBisStorageId partitionId, const char* string);
@ -283,9 +296,9 @@ Result fsExtendSaveDataFileSystem(FsSaveDataSpaceId saveDataSpaceId, u64 saveID,
/// Do not call this directly, see fs_dev.h. /// Do not call this directly, see fs_dev.h.
Result fsMountSdcard(FsFileSystem* out); Result fsMountSdcard(FsFileSystem* out);
Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save); Result fsMountSaveData(FsFileSystem* out, u8 inval, const FsSave *save);
Result fsMountSystemSaveData(FsFileSystem* out, u8 inval, FsSave *save); Result fsMountSystemSaveData(FsFileSystem* out, u8 inval, const FsSave *save);
Result fsOpenSaveDataIterator(FsSaveDataIterator* out, s32 saveDataSpaceId); Result fsOpenSaveDataIterator(FsSaveDataIterator* out, FsSaveDataSpaceId saveDataSpaceId);
Result fsOpenContentStorageFileSystem(FsFileSystem* out, FsContentStorageId content_storage_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 fsOpenDataStorageByCurrentProcess(FsStorage* out);
@ -306,14 +319,14 @@ Result fsGetGlobalAccessLogMode(u32* out_mode);
// todo: Rest of commands here // todo: Rest of commands here
// Wrapper(s) for fsCreateSaveDataFileSystemBySystemSaveDataId. // Wrapper(s) for fsCreateSaveDataFileSystemBySystemSaveDataId.
Result fsCreate_SystemSaveDataWithOwner(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, u128 userID, u64 ownerId, u64 size, u64 journalSize, u32 flags); Result fsCreate_SystemSaveDataWithOwner(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, AccountUid *userID, u64 ownerId, u64 size, u64 journalSize, u32 flags);
Result fsCreate_SystemSaveData(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, u64 size, u64 journalSize, u32 flags); Result fsCreate_SystemSaveData(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, u64 size, u64 journalSize, u32 flags);
/// FsFileSystem can be mounted with fs_dev for use with stdio, see fs_dev.h. /// FsFileSystem can be mounted with fs_dev for use with stdio, see fs_dev.h.
/// Wrapper(s) for fsMountSaveData. /// Wrapper(s) for fsMountSaveData.
/// See FsSave for titleID and userID. /// See FsSave for titleID and userID.
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID); Result fsMount_SaveData(FsFileSystem* out, u64 titleID, AccountUid *userID);
/// Wrapper for fsMountSystemSaveData. /// Wrapper for fsMountSystemSaveData.
/// WARNING: You can brick when writing to SystemSaveData, if the data is corrupted etc. /// WARNING: You can brick when writing to SystemSaveData, if the data is corrupted etc.
@ -340,16 +353,16 @@ Result fsOpenFileSystemWithId(FsFileSystem* out, u64 titleId, FsFileSystemType f
Result fsOpenFileSystemWithPatch(FsFileSystem* out, u64 titleId, FsFileSystemType fsType); /// [2.0.0+], like OpenFileSystemWithId but without content path. Result fsOpenFileSystemWithPatch(FsFileSystem* out, u64 titleId, FsFileSystemType fsType); /// [2.0.0+], like OpenFileSystemWithId but without content path.
// IFileSystem // IFileSystem
Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags); Result fsFsCreateFile(FsFileSystem* fs, const char* path, u64 size, u32 option);
Result fsFsDeleteFile(FsFileSystem* fs, const char* path); Result fsFsDeleteFile(FsFileSystem* fs, const char* path);
Result fsFsCreateDirectory(FsFileSystem* fs, const char* path); Result fsFsCreateDirectory(FsFileSystem* fs, const char* path);
Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path); Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path);
Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path); Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path);
Result fsFsRenameFile(FsFileSystem* fs, const char* cur_path, const char* new_path); Result fsFsRenameFile(FsFileSystem* fs, const char* cur_path, const char* new_path);
Result fsFsRenameDirectory(FsFileSystem* fs, const char* cur_path, const char* new_path); Result fsFsRenameDirectory(FsFileSystem* fs, const char* cur_path, const char* new_path);
Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsEntryType* out); Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsDirEntryType* out);
Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out); Result fsFsOpenFile(FsFileSystem* fs, const char* path, u32 mode, FsFile* out);
Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* out); Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, u32 mode, FsDir* out);
Result fsFsCommit(FsFileSystem* fs); Result fsFsCommit(FsFileSystem* fs);
Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out); Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out);
Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out); Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out);
@ -363,36 +376,36 @@ void fsFsClose(FsFileSystem* fs);
Result fsFsSetArchiveBit(FsFileSystem* fs, const char *path); Result fsFsSetArchiveBit(FsFileSystem* fs, const char *path);
// IFile // IFile
Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, u32 option, size_t* out); Result fsFileRead(FsFile* f, u64 off, void* buf, u64 read_size, u32 option, u64* bytes_read);
Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len, u32 option); Result fsFileWrite(FsFile* f, u64 off, const void* buf, u64 write_size, u32 option);
Result fsFileFlush(FsFile* f); Result fsFileFlush(FsFile* f);
Result fsFileSetSize(FsFile* f, u64 sz); Result fsFileSetSize(FsFile* f, u64 sz);
Result fsFileGetSize(FsFile* f, u64* out); Result fsFileGetSize(FsFile* f, u64* out);
Result fsFileOperateRange(FsFile* f, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out); /// [4.0.0+] Result fsFileOperateRange(FsFile* f, FsOperationId op_id, u64 off, u64 len, FsRangeInfo* out); /// [4.0.0+]
void fsFileClose(FsFile* f); void fsFileClose(FsFile* f);
// IDirectory // IDirectory
Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries, FsDirectoryEntry *buf); Result fsDirRead(FsDir* d, u64 inval, u64* total_entries, size_t max_entries, FsDirectoryEntry *buf);
Result fsDirGetEntryCount(FsDir* d, u64* count); Result fsDirGetEntryCount(FsDir* d, u64* count);
void fsDirClose(FsDir* d); void fsDirClose(FsDir* d);
// IStorage // IStorage
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len); Result fsStorageRead(FsStorage* s, u64 off, void* buf, u64 read_size);
Result fsStorageWrite(FsStorage* s, u64 off, const void* buf, size_t len); Result fsStorageWrite(FsStorage* s, u64 off, const void* buf, u64 write_size);
Result fsStorageFlush(FsStorage* s); Result fsStorageFlush(FsStorage* s);
Result fsStorageSetSize(FsStorage* s, u64 sz); Result fsStorageSetSize(FsStorage* s, u64 sz);
Result fsStorageGetSize(FsStorage* s, u64* out); Result fsStorageGetSize(FsStorage* s, u64* out);
Result fsStorageOperateRange(FsStorage* s, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out); /// [4.0.0+] Result fsStorageOperateRange(FsStorage* s, FsOperationId op_id, u64 off, u64 len, FsRangeInfo* out); /// [4.0.0+]
void fsStorageClose(FsStorage* s); void fsStorageClose(FsStorage* s);
// ISaveDataInfoReader // ISaveDataInfoReader
/// Read FsSaveDataInfo data into the buf array. /// Read FsSaveDataInfo data into the buf array.
Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, size_t* total_entries); Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, u64* total_entries);
void fsSaveDataIteratorClose(FsSaveDataIterator *s); void fsSaveDataIteratorClose(FsSaveDataIterator *s);
// IEventNotifier // IEventNotifier
Result fsEventNotifierGetEventHandle(FsEventNotifier* e, Handle* out); Result fsEventNotifierGetEventHandle(FsEventNotifier* e, Event* out, bool autoclear);
void fsEventNotifierClose(FsEventNotifier* e); void fsEventNotifierClose(FsEventNotifier* e);
// IDeviceOperator // IDeviceOperator

View File

@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
#include "../services/fs.h" #include "../services/fs.h"
Result fsldrInitialize(void); Result fsldrInitialize(void);
@ -15,4 +15,4 @@ Service* fsldrGetServiceSession(void);
Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out); Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out);
Result fsldrIsArchivedProgram(u64 pid, bool *out); Result fsldrIsArchivedProgram(u64 pid, bool *out);
Result fsldrSetCurrentProcess(void); Result fsldrSetCurrentProcess(void);

View File

@ -10,18 +10,7 @@
#include "../services/caps.h" #include "../services/caps.h"
#include "../kernel/event.h" #include "../kernel/event.h"
#include "../kernel/tmem.h" #include "../kernel/tmem.h"
#include "../display/native_window.h"
/// GameMovieTrimmer
typedef struct {
Service s; ///< IGameMovieTrimmer
TransferMemory tmem; ///< TransferMemory
} GrcGameMovieTrimmer;
/// GameMovieId
typedef struct {
CapsAlbumEntryId album_id; ///< \ref CapsAlbumEntryId
u8 reserved[0x28]; ///< Unused, always zero.
} GrcGameMovieId;
/// Stream type values for \ref grcdRead. /// Stream type values for \ref grcdRead.
typedef enum { typedef enum {
@ -29,7 +18,58 @@ typedef enum {
GrcStream_Audio = 1, ///< Audio stream with PcmFormat_Int16, 2 channels, and samplerate = 48000Hz. Official sw uses buffer size 0x1000. GrcStream_Audio = 1, ///< Audio stream with PcmFormat_Int16, 2 channels, and samplerate = 48000Hz. Official sw uses buffer size 0x1000.
} GrcStream; } GrcStream;
// Trimming /// GameMovieTrimmer
typedef struct {
Service s; ///< IGameMovieTrimmer
TransferMemory tmem; ///< TransferMemory
} GrcGameMovieTrimmer;
/// IMovieMaker
typedef struct {
Service a; ///< applet IMovieMaker
Service s; ///< grc IMovieMaker
Service video_proxy; ///< IHOSBinderDriver VideoProxy
Event recording_event; ///< Output Event from GetOffscreenLayerRecordingFinishReadyEvent with autoclear=false.
Event audio_event; ///< Output Event from GetOffscreenLayerAudioEncodeReadyEvent with autoclear=false.
TransferMemory tmem; ///< TransferMemory
NWindow win; ///< \ref NWindow
u64 layer_handle; ///< LayerHandle
bool layer_open; ///< Whether OpenOffscreenLayer was used successfully, indicating that CloseOffscreenLayer should be used during \ref grcMovieMakerClose.
bool started_flag; ///< Whether \ref grcMovieMakerStart was used successfully. This is also used by \ref grcMovieMakerAbort.
} GrcMovieMaker;
/// GameMovieId
typedef struct {
CapsAlbumEntryId album_id; ///< \ref CapsAlbumEntryId
u8 reserved[0x28]; ///< Unused, always zero.
} GrcGameMovieId;
/// OffscreenRecordingParameter
typedef struct {
u8 unk_x0[0x10]; ///< Unknown. Default value is 0.
u32 unk_x10; ///< Unknown. Must match value 0x103, which is the default value.
s32 video_bitrate; ///< VideoBitRate, 0 is invalid. Default value is 8000000.
s32 video_width; ///< VideoWidth, must match 1280 or 1920. Default value is 1280.
s32 video_height; ///< VideoHeight, must match 720 or 1080. Default value is 720.
s32 video_framerate; ///< VideoFrameRate, must match 30 or 60. Default value is 30.
s32 video_keyFrameInterval; ///< VideoKeyFrameInterval, 0 is invalid. Default value is 30.
s32 audio_bitrate; ///< AudioBitRate. Default value is 128000 ([5.0.0-5.1.0] 1536000).
s32 audio_samplerate; ///< AudioSampleRate, 0 is invalid. Default value is 48000.
s32 audio_channel_count; ///< AudioChannelCount. Must match 2, which is the default value.
s32 audio_sample_format; ///< \ref PcmFormat AudioSampleFormat. Must match PcmFormat_Int16, which is the default value.
s32 video_imageOrientation; ///< \ref AlbumImageOrientation VideoImageOrientation. Default value is ::AlbumImageOrientation_Unknown0.
u8 unk_x3c[0x44]; ///< Unknown. Default value is 0.
} GrcOffscreenRecordingParameter;
/// Default size for \ref grcCreateMovieMaker, this is the size used by official sw.
#define GRC_MOVIEMAKER_WORKMEMORY_SIZE_DEFAULT 0x6000000
///@name Trimming
///@{
/** /**
* @brief Creates a \ref GrcGameMovieTrimmer using \ref appletCreateGameMovieTrimmer, uses the cmds from it to trim the specified video, then closes it. * @brief Creates a \ref GrcGameMovieTrimmer using \ref appletCreateGameMovieTrimmer, uses the cmds from it to trim the specified video, then closes it.
@ -44,7 +84,90 @@ typedef enum {
*/ */
Result grcTrimGameMovie(GrcGameMovieId *dst_movieid, const GrcGameMovieId *src_movieid, size_t tmem_size, const void* thumbnail, s32 start, s32 end); Result grcTrimGameMovie(GrcGameMovieId *dst_movieid, const GrcGameMovieId *src_movieid, size_t tmem_size, const void* thumbnail, s32 start, s32 end);
// grc:d ///@}
///@name IMovieMaker
///@{
/**
* @brief Creates a \ref GrcOffscreenRecordingParameter with the default values, see \ref GrcOffscreenRecordingParameter for the default values.
* @param[out] param \ref GrcOffscreenRecordingParameter
*/
void grcCreateOffscreenRecordingParameter(GrcOffscreenRecordingParameter *param);
/**
* @brief Creates a \ref GrcMovieMaker using \ref appletCreateMovieMaker, and does the required initialization.
* @note See \ref appletCreateMovieMaker for the requirements for using this.
* @param[out] m \ref GrcMovieMaker
* @param[in] size TransferMemory WorkMemory size. See \ref GRC_MOVIEMAKER_WORKMEMORY_SIZE_DEFAULT.
*/
Result grcCreateMovieMaker(GrcMovieMaker *m, size_t size);
/**
* @brief Closes a \ref GrcMovieMaker.
* @note This also uses \ref grcMovieMakerAbort.
* @param m \ref GrcMovieMaker
*/
void grcMovieMakerClose(GrcMovieMaker *m);
/**
* @brief Gets the \ref NWindow for the specified MovieMaker.
* @param m \ref GrcMovieMaker
*/
static inline NWindow* grcMovieMakerGetNWindow(GrcMovieMaker *m) {
return &m->win;
}
/**
* @brief Starts recording with the specified MovieMaker and \ref GrcOffscreenRecordingParameter.
* @param m \ref GrcMovieMaker
* @param[in] param \ref GrcOffscreenRecordingParameter
*/
Result grcMovieMakerStart(GrcMovieMaker *m, const GrcOffscreenRecordingParameter *param);
/**
* @brief Aborts recording with the specified MovieMaker.
* @note This is used automatically by \ref grcMovieMakerClose.
* @note This will throw an error if \ref grcMovieMakerStart was not used previously, with the flag used for this being cleared afterwards on success.
* @param m \ref GrcMovieMaker
*/
Result grcMovieMakerAbort(GrcMovieMaker *m);
/**
* @brief Finishes recording with the specified MovieMaker.
* @note This automatically uses \ref grcMovieMakerAbort on error.
* @note The recorded video will not be accessible via the Album-applet since it's stored separately from other Album data.
* @param m \ref GrcMovieMaker
* @param width Width for the thumbnail, must be 1280.
* @param height Height for the thumbnail, must be 720.
* @param[in] userdata UserData input buffer for the JPEG thumbnail. Optional, can be NULL.
* @param[in] userdata_size Size of the UserData input buffer. Optional, can be 0. Must be <=0x400.
* @param[in] thumbnail RGBA8 image buffer containing the thumbnail. Optional, can be NULL.
* @param[in] thumbnail_size Size of the thumbnail buffer. Optional, can be 0.
* @param[out] entry Output \ref CapsApplicationAlbumEntry for the recorded video. Optional, can be NULL. Only available on [7.0.0+], if this is not NULL on pre-7.0.0 an error is thrown.
*/
Result grcMovieMakerFinish(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size, CapsApplicationAlbumEntry *entry);
/**
* @brief Gets the recording error with the specified MovieMaker.
* @param m \ref GrcMovieMaker
*/
Result grcMovieMakerGetError(GrcMovieMaker *m);
/**
* @brief Encodes audio sample data with the specified MovieMaker.
* @note This waits on the event and uses the cmd repeatedly until the entire input buffer is handled.
* @note If you don't use this the recorded video will be missing audio.
* @param m \ref GrcMovieMaker
* @param[in] buffer Audio buffer.
* @param[in] size Size of the buffer.
*/
Result grcMovieMakerEncodeAudioSample(GrcMovieMaker *m, const void* buffer, size_t size);
///@}
///@name grc:d
///@{
/// Initialize grc:d. /// Initialize grc:d.
Result grcdInitialize(void); Result grcdInitialize(void);
@ -70,3 +193,5 @@ Result grcdBegin(void);
*/ */
Result grcdRead(GrcStream stream, void* buffer, size_t size, u32 *unk, u32 *data_size, u64 *timestamp); Result grcdRead(GrcStream stream, void* buffer, size_t size, u32 *unk, u32 *data_size, u64 *timestamp);
///@}

View File

@ -222,6 +222,9 @@ typedef enum
TYPE_JOYCON_PAIR = BIT(2), TYPE_JOYCON_PAIR = BIT(2),
TYPE_JOYCON_LEFT = BIT(3), TYPE_JOYCON_LEFT = BIT(3),
TYPE_JOYCON_RIGHT = BIT(4), TYPE_JOYCON_RIGHT = BIT(4),
TYPE_SYSTEM_EXT = BIT(29),
TYPE_SYSTEM = BIT(30),
} HidControllerType; } HidControllerType;
typedef enum typedef enum
@ -240,6 +243,7 @@ typedef enum
COLORS_NONEXISTENT = BIT(1), COLORS_NONEXISTENT = BIT(1),
} HidControllerColorDescription; } HidControllerColorDescription;
/// HidControllerKeys
typedef enum typedef enum
{ {
KEY_A = BIT(0), ///< A KEY_A = BIT(0), ///< A
@ -327,6 +331,52 @@ typedef enum
HidJoyHoldType_Horizontal = 1, ///< Joy-Con held horizontally with HID state orientation adjustment, see \ref HidControllerLayoutType. HidJoyHoldType_Horizontal = 1, ///< Joy-Con held horizontally with HID state orientation adjustment, see \ref HidControllerLayoutType.
} HidJoyHoldType; } HidJoyHoldType;
/// DeviceType
typedef enum {
HidDeviceTypeBits_FullKey = BIT(0), ///< Pro Controller and Gc controller.
HidDeviceTypeBits_Unknown1 = BIT(1), ///< Unknown.
HidDeviceTypeBits_HandheldLeft = BIT(2), ///< Joy-Con/Famicom/NES left controller in handheld mode.
HidDeviceTypeBits_HandheldRight = BIT(3), ///< Joy-Con/Famicom/NES right controller in handheld mode.
HidDeviceTypeBits_JoyLeft = BIT(4), ///< Joy-Con left controller.
HidDeviceTypeBits_JoyRight = BIT(5), ///< Joy-Con right controller.
HidDeviceTypeBits_Palma = BIT(6), ///< Poké Ball Plus controller.
HidDeviceTypeBits_LarkLeftHVC = BIT(7), ///< Famicom left controller.
HidDeviceTypeBits_LarkRightHVC = BIT(8), ///< Famicom right controller (with microphone).
HidDeviceTypeBits_LarkLeftNES = BIT(9), ///< NES left controller.
HidDeviceTypeBits_LarkRightNES = BIT(10), ///< NES right controller.
HidDeviceTypeBits_SystemExt = BIT(15), ///< Generic external controller.
HidDeviceTypeBits_System = BIT(31), ///< Generic controller.
} HidDeviceTypeBits;
/// Internal DeviceType for [9.0.0+]. Converted to/from the pre-9.0.0 version of this by the hiddbg funcs.
typedef enum {
HidDeviceType_JoyRight1 = 1, ///< ::HidDeviceTypeBits_JoyRight
HidDeviceType_JoyLeft2 = 2, ///< ::HidDeviceTypeBits_JoyLeft
HidDeviceType_FullKey3 = 3, ///< ::HidDeviceTypeBits_FullKey
HidDeviceType_JoyLeft4 = 4, ///< ::HidDeviceTypeBits_JoyLeft
HidDeviceType_JoyRight5 = 5, ///< ::HidDeviceTypeBits_JoyRight
HidDeviceType_FullKey6 = 6, ///< ::HidDeviceTypeBits_FullKey
HidDeviceType_LarkLeftHVC = 7, ///< ::HidDeviceTypeBits_LarkLeftHVC
HidDeviceType_LarkRightHVC = 8, ///< ::HidDeviceTypeBits_LarkRightHVC
HidDeviceType_LarkLeftNES = 9, ///< ::HidDeviceTypeBits_LarkLeftNES
HidDeviceType_LarkRightNES = 10, ///< ::HidDeviceTypeBits_LarkRightNES
HidDeviceType_Palma = 12, ///< [9.0.0+] ::HidDeviceTypeBits_Palma
HidDeviceType_FullKey13 = 13, ///< ::HidDeviceTypeBits_FullKey
HidDeviceType_FullKey15 = 15, ///< ::HidDeviceTypeBits_FullKey
HidDeviceType_System19 = 19, ///< ::HidDeviceTypeBits_System with HidControllerType |= TYPE_PROCONTROLLER.
HidDeviceType_System20 = 20, ///< ::HidDeviceTypeBits_System with HidControllerType |= TYPE_JOYCON_PAIR.
HidDeviceType_System21 = 21, ///< ::HidDeviceTypeBits_System with HidControllerType |= TYPE_JOYCON_PAIR.
} HidDeviceType;
/// NpadInterfaceType
typedef enum
{
NpadInterfaceType_Bluetooth = 1, ///< Bluetooth.
NpadInterfaceType_Rail = 2, ///< Rail.
NpadInterfaceType_USB = 3, ///< USB.
NpadInterfaceType_Unknown4 = 4, ///< Unknown.
} HidNpadInterfaceType;
typedef struct touchPosition typedef struct touchPosition
{ {
u32 id; u32 id;
@ -666,7 +716,7 @@ HidControllerType hidGetControllerType(HidControllerID id);
void hidGetControllerColors(HidControllerID id, HidControllerColors *colors); void hidGetControllerColors(HidControllerID id, HidControllerColors *colors);
bool hidIsControllerConnected(HidControllerID id); bool hidIsControllerConnected(HidControllerID id);
/// Gets the DeviceType for the specified controller. /// Gets the \ref HidDeviceTypeBits for the specified controller.
u32 hidGetControllerDeviceType(HidControllerID id); u32 hidGetControllerDeviceType(HidControllerID id);
/// Gets the flags for the specified controller. /// Gets the flags for the specified controller.
@ -789,3 +839,7 @@ Result hidGetSevenSixAxisSensorFusionStrength(float *strength);
/// Resets the timestamp for the SevenSixAxisSensor. Only available on [6.0.0+]. /// Resets the timestamp for the SevenSixAxisSensor. Only available on [6.0.0+].
Result hidResetSevenSixAxisSensorTimestamp(void); Result hidResetSevenSixAxisSensorTimestamp(void);
/// Gets the \ref HidNpadInterfaceType for the specified controller.
/// Only available on [4.0.0+].
Result hidGetNpadInterfaceType(HidControllerID id, u8 *out);

View File

@ -8,16 +8,27 @@
#include "../services/hid.h" #include "../services/hid.h"
#include "../services/sm.h" #include "../services/sm.h"
/// HdlsDeviceInfo /// HdlsDeviceInfo, for [7.0.0-8.1.0].
typedef struct { typedef struct {
u32 type; ///< Only one bit can be set. BIT(N*4+0) = Pro-Controller, BIT(N*4+1) = Joy-Con Left, BIT(N*4+2) = Joy-Con Right, BIT(N*4+3) = invalid. Where N is 0-1. BIT(8-10) = Pro-Controller, BIT(11) = Famicom-Controller, BIT(12) = Famicom-Controller II with microphone, BIT(13) = NES-Controller(DeviceType=0x200), BIT(14) = NES-Controller(DeviceType=0x400), BIT(15-16) = invalid, BIT(17) = unknown(DeviceType=0x8000), BIT(18-20) = invalid, BIT(21-23) = unknown(DeviceType=0x80000000). u32 deviceTypeInternal; ///< Only one bit can be set. BIT(N*4+0) = Pro-Controller, BIT(N*4+1) = Joy-Con Left, BIT(N*4+2) = Joy-Con Right, BIT(N*4+3) = invalid. Where N is 0-1. BIT(8-10) = Pro-Controller, BIT(11) = Famicom-Controller, BIT(12) = Famicom-Controller II with microphone, BIT(13) = NES-Controller(DeviceType=0x200), BIT(14) = NES-Controller(DeviceType=0x400), BIT(15-16) = invalid, BIT(17) = unknown(DeviceType=0x8000), BIT(18-20) = invalid, BIT(21-23) = unknown(DeviceType=0x80000000).
u32 singleColorBody; ///< RGBA Single Body Color u32 singleColorBody; ///< RGBA Single Body Color.
u32 singleColorButtons; ///< RGBA Single Buttons Color u32 singleColorButtons; ///< RGBA Single Buttons Color.
u8 type2; ///< Additional type field used with the above type field (only applies to type bit0-bit2 and bit21), if the value doesn't match one of the following a default is used. Type Pro-Controller: value 0x3 indicates that the controller is connected via USB. Type BIT(21): value 0x3 = unknown. When value is 0x2, state is merged with an existing controller (when the type value is compatible with this). Otherwise, it's a dedicated controller. u8 npadInterfaceType; ///< \ref HidNpadInterfaceType. Additional type field used with the above type field (only applies to type bit0-bit2 and bit21), if the value doesn't match one of the following a default is used. Type Pro-Controller: value 0x3 indicates that the controller is connected via USB. Type BIT(21): value 0x3 = unknown. When value is 0x2, state is merged with an existing controller (when the type value is compatible with this). Otherwise, it's a dedicated controller.
u8 pad[0x3]; ///< Padding u8 pad[0x3]; ///< Padding.
} HiddbgHdlsDeviceInfoV7;
/// HdlsDeviceInfo, for [9.0.0+]. Converted to/from \ref HiddbgHdlsDeviceInfoV7 on prior sysvers.
typedef struct {
u8 deviceType; ///< \ref HidDeviceType
u8 npadInterfaceType; ///< \ref HidNpadInterfaceType. Additional type field used with the above type field (only applies to ::HidDeviceType_JoyRight1, ::HidDeviceType_JoyLeft2, ::HidDeviceType_FullKey3, and ::HidDeviceType_System19), if the value doesn't match one of the following a default is used. ::HidDeviceType_FullKey3: ::NpadInterfaceType_USB indicates that the controller is connected via USB. :::HidDeviceType_System19: ::NpadInterfaceType_USB = unknown. When value is ::NpadInterfaceType_Rail, state is merged with an existing controller (with ::HidDeviceType_JoyRight1 / ::HidDeviceType_JoyLeft2). Otherwise, it's a dedicated controller.
u8 pad[0x2]; ///< Padding.
u32 singleColorBody; ///< RGBA Single Body Color.
u32 singleColorButtons; ///< RGBA Single Buttons Color.
u32 colorLeftGrip; ///< [9.0.0+] RGBA Left Grip Color.
u32 colorRightGrip; ///< [9.0.0+] RGBA Right Grip Color.
} HiddbgHdlsDeviceInfo; } HiddbgHdlsDeviceInfo;
/// HdlsState /// HdlsState, for [7.0.0-8.1.0].
typedef struct { typedef struct {
u8 powerConnected; ///< powerConnected for the main PowerInfo, see \ref HidFlags. u8 powerConnected; ///< powerConnected for the main PowerInfo, see \ref HidFlags.
u8 flags; ///< ORRed with powerConnected to set the value of the first byte for \ref HidFlags. For example, value 1 here will set isCharging for the main PowerInfo. u8 flags; ///< ORRed with powerConnected to set the value of the first byte for \ref HidFlags. For example, value 1 here will set isCharging for the main PowerInfo.
@ -27,6 +38,16 @@ typedef struct {
JoystickPosition joysticks[JOYSTICK_NUM_STICKS]; ///< \ref JoystickPosition JoystickPosition joysticks[JOYSTICK_NUM_STICKS]; ///< \ref JoystickPosition
u8 unk_x20; ///< Unused for input. Set with output from \ref hiddbgDumpHdlsStates. Not set by \ref hiddbgGetAbstractedPadsState. u8 unk_x20; ///< Unused for input. Set with output from \ref hiddbgDumpHdlsStates. Not set by \ref hiddbgGetAbstractedPadsState.
u8 padding[0x3]; ///< Padding u8 padding[0x3]; ///< Padding
} HiddbgHdlsStateV7;
/// HdlsState, for [9.0.0+]. Converted to/from \ref HiddbgHdlsDeviceInfoV7 on prior sysvers.
typedef struct {
u32 batteryCharge; ///< batteryCharge for the main PowerInfo, see \ref HidPowerInfo.
u32 flags; ///< Used to set the main PowerInfo for \ref HidFlags. BIT(0) -> powerConnected, BIT(1) -> isCharging.
u64 buttons; ///< See \ref HidControllerKeys. [9.0.0+] Masked with 0xfffffffff00fffff.
JoystickPosition joysticks[JOYSTICK_NUM_STICKS]; ///< \ref JoystickPosition
u8 unk_x20; ///< Unused for input. Set with output from \ref hiddbgDumpHdlsStates.
u8 padding[0x3]; ///< Padding
} HiddbgHdlsState; } HiddbgHdlsState;
/// HdlsNpadAssignmentEntry /// HdlsNpadAssignmentEntry
@ -46,14 +67,29 @@ typedef struct {
HiddbgHdlsNpadAssignmentEntry entries[0x10]; ///< \ref HiddbgHdlsNpadAssignmentEntry HiddbgHdlsNpadAssignmentEntry entries[0x10]; ///< \ref HiddbgHdlsNpadAssignmentEntry
} HiddbgHdlsNpadAssignment; } HiddbgHdlsNpadAssignment;
/// HdlsStateListEntry /// HdlsStateListEntryV7, for [7.0.0-8.1.0].
typedef struct {
u64 HdlsHandle; ///< HdlsHandle
HiddbgHdlsDeviceInfoV7 device; ///< \ref HiddbgHdlsDeviceInfoV7. With \ref hiddbgApplyHdlsStateList this is only used when creating new devices.
HiddbgHdlsStateV7 state; ///< \ref HiddbgHdlsState
} HiddbgHdlsStateListEntryV7;
/// HdlsStateListV7, for [7.0.0-8.1.0]. This contains a list of all controllers, including non-virtual controllers.
typedef struct {
s32 total_entries; ///< Total entries for the below entries.
u32 pad; ///< Padding
HiddbgHdlsStateListEntryV7 entries[0x10]; ///< \ref HiddbgHdlsStateListEntryV7
} HiddbgHdlsStateListV7;
/// HdlsStateListEntry, for [9.0.0+]. Converted to/from \ref HiddbgHdlsStateListEntryV7 on prior sysvers.
typedef struct { typedef struct {
u64 HdlsHandle; ///< HdlsHandle u64 HdlsHandle; ///< HdlsHandle
HiddbgHdlsDeviceInfo device; ///< \ref HiddbgHdlsDeviceInfo. With \ref hiddbgApplyHdlsStateList this is only used when creating new devices. HiddbgHdlsDeviceInfo device; ///< \ref HiddbgHdlsDeviceInfo. With \ref hiddbgApplyHdlsStateList this is only used when creating new devices.
HiddbgHdlsState state; ///< \ref HiddbgHdlsState alignas(8) HiddbgHdlsState state; ///< \ref HiddbgHdlsState
} HiddbgHdlsStateListEntry; } HiddbgHdlsStateListEntry;
/// HdlsStateList. This contains a list of all controllers, including non-virtual controllers. /// HdlsStateList, for [9.0.0+]. Converted to/from \ref HiddbgHdlsStateListV7 on prior sysvers.
/// This contains a list of all controllers, including non-virtual controllers.
typedef struct { typedef struct {
s32 total_entries; ///< Total entries for the below entries. s32 total_entries; ///< Total entries for the below entries.
u32 pad; ///< Padding u32 pad; ///< Padding
@ -62,16 +98,16 @@ typedef struct {
/// AbstractedPadState /// AbstractedPadState
typedef struct { typedef struct {
u32 type; ///< Type. Converted to HiddbgHdlsDeviceInfo::type internally by \ref hiddbgSetAutoPilotVirtualPadState. BIT(0) -> BIT(0), BIT(1) -> BIT(15), BIT(2-3) -> BIT(1-2), BIT(4-5) -> BIT(1-2), BIT(6) -> BIT(3). BIT(7-11) -> BIT(11-15), BIT(12-14) -> BIT(12-14), BIT(15) -> BIT(17), BIT(31) -> BIT(21). u32 type; ///< Type. Converted to HiddbgHdlsDeviceInfoV7::type internally by \ref hiddbgSetAutoPilotVirtualPadState. BIT(0) -> BIT(0), BIT(1) -> BIT(15), BIT(2-3) -> BIT(1-2), BIT(4-5) -> BIT(1-2), BIT(6) -> BIT(3). BIT(7-11) -> BIT(11-15), BIT(12-14) -> BIT(12-14), BIT(15) -> BIT(17), BIT(31) -> BIT(21).
u8 flags; ///< Flags. Only bit0 is used by \ref hiddbgSetAutoPilotVirtualPadState: when clear it will skip using the rest of the input and run \ref hiddbgUnsetAutoPilotVirtualPadState internally. u8 flags; ///< Flags. Only bit0 is used by \ref hiddbgSetAutoPilotVirtualPadState: when clear it will skip using the rest of the input and run \ref hiddbgUnsetAutoPilotVirtualPadState internally.
u8 pad[0x3]; ///< Padding u8 pad[0x3]; ///< Padding
u32 singleColorBody; ///< RGBA Single Body Color u32 singleColorBody; ///< RGBA Single Body Color
u32 singleColorButtons; ///< RGBA Single Buttons Color u32 singleColorButtons; ///< RGBA Single Buttons Color
u8 type2; ///< See HiddbgHdlsDeviceInfo::type2. u8 npadInterfaceType; ///< See HiddbgHdlsDeviceInfo::npadInterfaceType.
u8 pad2[0x3]; ///< Padding u8 pad2[0x3]; ///< Padding
HiddbgHdlsState state; ///< State HiddbgHdlsStateV7 state; ///< State
u8 unused[0x60]; ///< Unused with \ref hiddbgSetAutoPilotVirtualPadState. Not set by \ref hiddbgGetAbstractedPadsState. u8 unused[0x60]; ///< Unused with \ref hiddbgSetAutoPilotVirtualPadState. Not set by \ref hiddbgGetAbstractedPadsState.
} HiddbgAbstractedPadState; } HiddbgAbstractedPadState;
@ -90,20 +126,30 @@ Result hiddbgUpdateDesignInfo(u32 colorBody, u32 colorButtons, u32 colorLeftGrip
/// This doesn't seem to be usable? /// This doesn't seem to be usable?
Result hiddbgReadSerialFlash(u32 offset, void* buffer, size_t size, u64 UniquePadId); Result hiddbgReadSerialFlash(u32 offset, void* buffer, size_t size, u64 UniquePadId);
/// Gets a list of AbstractedPadHandles, where AbstractedPadHandles is the output array with max entries = count. total_entries is total entries written to the output array. Only available with [5.0.0+]. /// Gets the internal DeviceType for the specified controller. See hidsys.h for UniquePadId.
/// Only available with [6.0.0+].
/// Pre-9.0.0 the output is an u32, with [9.0.0+] it's an u8.
Result hiddbgGetUniquePadDeviceTypeSetInternal(u64 UniquePadId, u32 *out);
/// Gets a list of AbstractedPadHandles, where AbstractedPadHandles is the output array with max entries = count. total_entries is total entries written to the output array.
/// Only available with [5.0.0-8.1.0].
Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *total_entries); Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *total_entries);
/// Gets the state for the specified AbstractedPadHandle. Only available with [5.0.0+]. /// Gets the state for the specified AbstractedPadHandle.
/// Only available with [5.0.0-8.1.0].
Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadState *state); Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadState *state);
/// Similar to \ref hiddbgGetAbstractedPadHandles except this also returns the state for each pad in output array states. Only available with [5.0.0+]. /// Similar to \ref hiddbgGetAbstractedPadHandles except this also returns the state for each pad in output array states.
/// Only available with [5.0.0-8.1.0].
Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedPadState *states, s32 count, s32 *total_entries); Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedPadState *states, s32 count, s32 *total_entries);
/// Sets AutoPilot state for the specified pad. /// Sets AutoPilot state for the specified pad.
/// AbstractedVirtualPadId can be any unique value as long as it's within bounds. For example, 0-7 is usable. /// AbstractedVirtualPadId can be any unique value as long as it's within bounds. For example, 0-7 is usable.
/// Only available with [5.0.0-8.1.0].
Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const HiddbgAbstractedPadState *state); Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const HiddbgAbstractedPadState *state);
/// Clears AutoPilot state for the specified pad set by \ref hiddbgSetAutoPilotVirtualPadState. /// Clears AutoPilot state for the specified pad set by \ref hiddbgSetAutoPilotVirtualPadState.
/// Only available with [5.0.0-8.1.0].
Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId); Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId);
/// Clears AutoPilot state for all pads set by \ref hiddbgSetAutoPilotVirtualPadState. /// Clears AutoPilot state for all pads set by \ref hiddbgSetAutoPilotVirtualPadState.

View File

@ -43,6 +43,11 @@ Result hidsysEnableAppletToGetInput(bool enable);
**/ **/
Result hidsysAcquireHomeButtonEventHandle(Event* event_out); Result hidsysAcquireHomeButtonEventHandle(Event* event_out);
/**
* @brief Returns an event that fires when the capture button is pressed. This event does not auto clear.
**/
Result hidsysAcquireCaptureButtonEventHandle(Event* event_out);
Result hidsysActivateHomeButton(void); Result hidsysActivateHomeButton(void);
Result hidsysActivateSleepButton(void); Result hidsysActivateSleepButton(void);
Result hidsysActivateCaptureButton(void); Result hidsysActivateCaptureButton(void);

View File

@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
#include "../services/fs.h" #include "../services/fs.h"
typedef struct { typedef struct {
@ -31,10 +31,10 @@ Result lrLrRedirectProgramPath(LrLocationResolver* lr, u64 tid, const char *path
Result lrLrResolveApplicationControlPath(LrLocationResolver* lr, u64 tid, char *out); Result lrLrResolveApplicationControlPath(LrLocationResolver* lr, u64 tid, char *out);
Result lrLrResolveApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, char *out); Result lrLrResolveApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, char *out);
Result lrLrResolveDataPath(LrLocationResolver* lr, u64 tid, char *out); Result lrLrResolveDataPath(LrLocationResolver* lr, u64 tid, char *out);
Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, const char *path); Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path);
Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, const char *path); Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path);
Result lrLrResolveLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out); Result lrLrResolveApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out);
Result lrLrRedirectLegalInformationPath(LrLocationResolver* lr, u64 tid, const char *path); Result lrLrRedirectApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path);
Result lrLrRefresh(LrLocationResolver* lr); Result lrLrRefresh(LrLocationResolver* lr);
// IRegisteredLocationResolver // IRegisteredLocationResolver

View File

@ -1,7 +1,7 @@
/** /**
* @file ncm.h * @file ncm.h
* @brief Content Manager (ncm) service IPC wrapper. * @brief Content Manager (ncm) service IPC wrapper.
* @author zhuowei & Adubbz * @author Adubbz & zhuowei
* @copyright libnx Authors * @copyright libnx Authors
*/ */
#pragma once #pragma once
@ -9,102 +9,190 @@
#include "../services/fs.h" #include "../services/fs.h"
#include "../services/sm.h" #include "../services/sm.h"
typedef enum { /// ContentStorage
NcmContentType_CNMT = 0,
NcmContentType_Program = 1,
NcmContentType_Data = 2,
NcmContentType_Icon = 3,
NcmContentType_Doc = 4,
NcmContentType_Info = 5,
} NcmContentType;
typedef enum {
NcmContentMetaType_SystemProgram = 0x01,
NcmContentMetaType_SystemData = 0x02,
NcmContentMetaType_SystemUpdate = 0x03,
NcmContentMetaType_BootImagePackage = 0x04,
NcmContentMetaType_BootImagePackageSafe = 0x05,
NcmContentMetaType_Application = 0x80,
NcmContentMetaType_Patch = 0x81,
NcmContentMetaType_AddOnContent = 0x82,
NcmContentMetaType_Delta = 0x83,
} NcmContentMetaType;
typedef enum {
NcmContentMetaAttribute_Exfat = (1 << 0),
NcmContentMetaAttribute_Rebootless = (1 << 1),
} NcmContentMetaAttribute;
typedef struct { typedef struct {
Service s; Service s; ///< IContentStorage
} NcmContentStorage; } NcmContentStorage;
/// ContentMetaDatabase
typedef struct { typedef struct {
Service s; Service s; ///< IContentMetaDatabase
} NcmContentMetaDatabase; } NcmContentMetaDatabase;
/// ContentType
typedef enum {
NcmContentType_Meta = 0, ///< Meta
NcmContentType_Program = 1, ///< Program
NcmContentType_Data = 2, ///< Data
NcmContentType_Control = 3, ///< Control
NcmContentType_HtmlDocument = 4, ///< HtmlDocument
NcmContentType_LegalInformation = 5, ///< LegalInformation
NcmContentType_DeltaFragment = 6, ///< DeltaFragment
} NcmContentType;
/// ContentMetaType
typedef enum {
NcmContentMetaType_Unknown = 0x0, ///< Unknown
NcmContentMetaType_SystemProgram = 0x1, ///< SystemProgram
NcmContentMetaType_SystemData = 0x2, ///< SystemData
NcmContentMetaType_SystemUpdate = 0x3, ///< SystemUpdate
NcmContentMetaType_BootImagePackage = 0x4, ///< BootImagePackage
NcmContentMetaType_BootImagePackageSafe = 0x5, ///< BootImagePackageSafe
NcmContentMetaType_Application = 0x80, ///< Application
NcmContentMetaType_Patch = 0x81, ///< Patch
NcmContentMetaType_AddOnContent = 0x82, ///< AddOnContent
NcmContentMetaType_Delta = 0x83, ///< Delta
} NcmContentMetaType;
/// ContentMetaAttribute
typedef enum {
NcmContentMetaAttribute_None = 0, ///< None
NcmContentMetaAttribute_IncludesExFatDriver = BIT(0), ///< IncludesExFatDriver
NcmContentMetaAttribute_Rebootless = BIT(1), ///< Rebootless
} NcmContentMetaAttribute;
/// ContentInstallType
typedef enum {
NcmContentInstallType_Full = 0, ///< Full
NcmContentInstallType_FragmentOnly = 1, ///< FragmentOnly
NcmContentInstallType_Unknown = 7, ///< Unknown
} NcmContentInstallType;
/// NcaId
typedef struct { typedef struct {
u8 c[0x10]; u8 c[0x10]; ///< Id
} NcmNcaId; } NcmNcaId;
/// ContentMetaKey
typedef struct { typedef struct {
u64 titleId; u64 title_id; ///< Title id.
u32 version; u32 version; ///< Title version.
u8 type; u8 type; ///< \ref NcmContentMetaType
u8 flags; u8 install_type; ///< \ref NcmContentInstallType
u8 padding[2]; u8 padding[2]; ///< Padding.
} NcmMetaRecord; } NcmContentMetaKey;
/// ApplicationContentMetaKey
typedef struct { typedef struct {
NcmNcaId ncaId; NcmContentMetaKey key; ///< \ref NcmContentMetaKey
u8 size[0x6]; u64 application_id; ///< Title id of an application.
u8 type;
u8 padding;
} NcmContentRecord;
typedef struct {
u16 numExtraBytes; ///< Size of optional struct that comes after this one.
u16 numContentRecords; ///< Number of NcmContentRecord entries after the extra bytes.
u16 numMetaRecords; ///< Number of NcmMetaRecord entries that come after the NcmContentRecords.
u16 padding; ///< Always zero.
} NcmContentMetaRecordsHeader;
typedef struct {
NcmMetaRecord metaRecord;
u64 baseTitleId;
} NcmApplicationContentMetaKey; } NcmApplicationContentMetaKey;
/// ContentInfo
typedef struct {
NcmNcaId content_id; ///< \ref NcmNcaId
u8 size[0x6]; ///< Content size.
u8 content_type; ///< \ref NcmContentType.
u8 id_offset; ///< Offset of this content. Unused by most applications.
} NcmContentInfo;
/// Used by system updates. They share the exact same struct as NcmContentMetaKey
typedef NcmContentMetaKey NcmContentMetaInfo;
/// ContentMetaHeader
typedef struct {
u16 extended_header_size; ///< Size of optional struct that comes after this one.
u16 content_count; ///< Number of NcmContentInfos after the extra bytes.
u16 content_meta_count; ///< Number of NcmContentMetaInfos that come after the NcmContentInfos.
u8 attributes; ///< Usually None (0).
u8 storage_id; ///< Usually None (0).
} NcmContentMetaHeader;
/// ApplicationMetaExtendedHeader
typedef struct {
u64 patch_id; ///< Title id of this application's patch.
u32 required_system_version; ///< Firmware version required by this application.
u32 required_application_version; ///< [9.0.0+] Owner application version required by this application. Previously padding.
} NcmApplicationMetaExtendedHeader;
/// PatchMetaExtendedHeader
typedef struct {
u64 application_id; ///< Title id of this patch's corresponding application.
u32 required_system_version; ///< Firmware version required by this patch.
u32 extended_data_size; ///< Size of the extended data following the NcmContentInfos.
u8 reserved[0x8]; ///< Unused.
} NcmPatchMetaExtendedHeader;
/// AddOnContentMetaExtendedHeader
typedef struct {
u64 application_id; ///< Title id of this add-on-content's corresponding application.
u32 required_application_version; ///< Version of the application required by this add-on-content.
u32 padding; ///< Padding.
} NcmAddOnContentMetaExtendedHeader;
/// SystemUpdateMetaExtendedHeader
typedef struct {
u32 extended_data_size; ///< Size of the extended data after NcmContentInfos and NcmContentMetaInfos.
} NcmSystemUpdateMetaExtendedHeader;
Result ncmInitialize(void); Result ncmInitialize(void);
void ncmExit(void); void ncmExit(void);
Service* ncmGetServiceSession(void); Service* ncmGetServiceSession(void);
Result ncmOpenContentStorage(FsStorageId storage, NcmContentStorage* out); Result ncmCreateContentStorage(FsStorageId storage_id);
Result ncmOpenContentMetaDatabase(FsStorageId storage, NcmContentMetaDatabase* out); Result ncmCreateContentMetaDatabase(FsStorageId storage_id);
Result ncmVerifyContentStorage(FsStorageId storage_id);
Result ncmVerifyContentMetaDatabase(FsStorageId storage_id);
Result ncmOpenContentStorage(NcmContentStorage* out_content_storage, FsStorageId storage_id);
Result ncmOpenContentMetaDatabase(NcmContentMetaDatabase* out_content_meta_database, FsStorageId storage_id);
Result ncmCloseContentStorageForcibly(FsStorageId storage_id); ///< [1.0.0]
Result ncmCloseContentMetaDatabaseForcibly(FsStorageId storage_id); ///< [1.0.0]
Result ncmCleanupContentMetaDatabase(FsStorageId storage_id);
Result ncmActivateContentStorage(FsStorageId storage_id); ///< [2.0.0+]
Result ncmInactivateContentStorage(FsStorageId storage_id); ///< [2.0.0+]
Result ncmActivateContentMetaDatabase(FsStorageId storage_id); ///< [2.0.0+]
Result ncmInactivateContentMetaDatabase(FsStorageId storage_id); ///< [2.0.0+]
Result ncmInvalidateRightsIdCache(void); ///< [9.0.0+]
Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* outputId); void ncmContentStorageClose(NcmContentStorage* cs);
Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId, u64 size); Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* out_id);
Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId); Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id, u64 size);
Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId, u64 offset, const void* srcData, size_t srcDataSize); Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id);
Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId); Result ncmContentStorageHasPlaceHolder(NcmContentStorage* cs, bool* out, const NcmNcaId* placeholder_id);
Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* registeredId); Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 offset, const void* data, size_t data_size);
Result ncmContentStorageHas(NcmContentStorage* cs, const NcmNcaId* ncaId, bool* out); Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id);
Result ncmContentStorageGetPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize); Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* content_id);
Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize); Result ncmContentStorageHas(NcmContentStorage* cs, bool* out, const NcmNcaId* content_id);
Result ncmContentStorageGetPath(NcmContentStorage* cs, char* out_path, size_t out_size, const NcmNcaId* content_id);
Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const char* out_path, size_t out_size, const NcmNcaId* placeholder_id);
Result ncmContentStorageCleanupAllPlaceHolder(NcmContentStorage* cs); Result ncmContentStorageCleanupAllPlaceHolder(NcmContentStorage* cs);
Result ncmContentStorageGetSize(NcmContentStorage* cs, const NcmNcaId* ncaId, u64* out); Result ncmContentStorageListPlaceHolder(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count);
Result ncmContentStorageGetContentCount(NcmContentStorage* cs, u32* out_count);
Result ncmContentStorageListContentId(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count, u32 start_offset);
Result ncmContentStorageGetSizeFromContentId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* content_id);
Result ncmContentStorageDisableForcibly(NcmContentStorage* cs); Result ncmContentStorageDisableForcibly(NcmContentStorage* cs);
Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, const NcmNcaId* ncaId, u64 offset, void* outBuf, size_t bufSize); Result ncmContentStorageRevertToPlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, const NcmNcaId* old_content_id, const NcmNcaId* new_content_id); ///< [2.0.0+]
Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, const NcmNcaId* ncaId, FsRightsId* rightsIdOut, u32* keyGenerationOut); Result ncmContentStorageSetPlaceHolderSize(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 size); ///< [2.0.0+]
Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, void* out_data, size_t out_data_size, const NcmNcaId* content_id, u64 offset); ///< [2.0.0+]
Result ncmContentStorageGetRightsIdFromPlaceHolderId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id); ///< [2.0.0+]
Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* content_id); ///< [2.0.0+]
Result ncmContentStorageWriteContentForDebug(NcmContentStorage* cs, const NcmNcaId* content_id, u64 offset, const void* data, size_t data_size); ///< [2.0.0+]
Result ncmContentStorageGetFreeSpaceSize(NcmContentStorage* cs, u64* out_size); ///< [2.0.0+]
Result ncmContentStorageGetTotalSpaceSize(NcmContentStorage* cs, u64* out_size); ///< [2.0.0+]
Result ncmContentStorageFlushPlaceHolder(NcmContentStorage* cs); ///< [3.0.0+]
Result ncmContentStorageGetSizeFromPlaceHolderId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* placeholder_id); ///< [4.0.0+]
Result ncmContentStorageRepairInvalidFileAttribute(NcmContentStorage* cs); ///< [4.0.0+]
Result ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id, const NcmNcaId* cache_content_id); ///< [8.0.0+]
Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 inDataSize, const NcmContentMetaRecordsHeader* srcRecordsData); void ncmContentMetaDatabaseClose(NcmContentMetaDatabase* db);
Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 outDataSize, NcmContentMetaRecordsHeader* outRecordsData, u64* sizeRead); Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, const void* data, u64 data_size);
Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmMetaRecord *record); Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u64* out_size, void* out_data, u64 out_data_size);
Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmContentType contentType, const NcmMetaRecord* record, NcmNcaId* out); Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmContentMetaKey *key);
Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u32 index, NcmContentRecord* contentRecordsOut, size_t contentRecordsBufSize, u32* numEntriesRead); Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type);
Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32 titleType, u64 titleIdExact, u64 titleIdLow, u64 titleIdHigh, NcmMetaRecord* metaRecordsOut, size_t metaRecordsBufSize, u32* numEntriesWritten, u32* numEntriesTotal); Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, u32* out_entries_written, NcmContentInfo* out_info, size_t out_info_size, const NcmContentMetaKey* key, u32 start_index);
Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, u64 titleId, NcmMetaRecord* out); Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type, u64 application_title_id, u64 title_id_min, u64 title_id_max, NcmContentInstallType install_type);
Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u8 filter, NcmApplicationContentMetaKey* outBuf, size_t outBufSize, u32* numEntriesWritten, u32* numEntriesTotal); Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, NcmContentMetaKey* out_key, u64 title_id);
Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, const NcmMetaRecord* record, bool* out); Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmApplicationContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type);
Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key);
Result ncmContentMetaDatabaseHasAll(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* keys, size_t keys_size);
Result ncmContentMetaDatabaseGetSize(NcmContentMetaDatabase* db, u64* out_size, const NcmContentMetaKey* key);
Result ncmContentMetaDatabaseGetRequiredSystemVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key);
Result ncmContentMetaDatabaseGetPatchId(NcmContentMetaDatabase* db, u64* out_patch_id, const NcmContentMetaKey* key);
Result ncmContentMetaDatabaseDisableForcibly(NcmContentMetaDatabase* db); Result ncmContentMetaDatabaseDisableForcibly(NcmContentMetaDatabase* db);
Result ncmContentMetaDatabaseLookupOrphanContent(NcmContentMetaDatabase* db, bool* out_orphaned, size_t out_orphaned_size, const NcmNcaId* content_ids, size_t content_ids_size);
Result ncmContentMetaDatabaseCommit(NcmContentMetaDatabase* db); Result ncmContentMetaDatabaseCommit(NcmContentMetaDatabase* db);
Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u8* out); Result ncmContentMetaDatabaseHasContent(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key, const NcmNcaId* content_id);
Result ncmContentMetaDatabaseListContentMetaInfo(NcmContentMetaDatabase* db, u32* out_entries_written, void* out_meta_info, size_t out_meta_info_size, const NcmContentMetaKey* key, u32 start_index);
Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u8* out);
Result ncmContentMetaDatabaseGetRequiredApplicationVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key); ///< [2.0.0+]
Result ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type, u8 id_offset); ///< [5.0.0+]

View File

@ -1,13 +1,13 @@
/** /**
* @file nifm.h * @file nifm.h
* @brief Network interface service IPC wrapper. * @brief Network interface service IPC wrapper.
* @author shadowninja108, shibboleet, exelix * @author shadowninja108, shibboleet, exelix, yellows8
* @copyright libnx Authors * @copyright libnx Authors
*/ */
#pragma once #pragma once
#include "../kernel/ipc.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
typedef enum { typedef enum {
NifmServiceType_NotInitialized = 0, ///< Initializes nifm:u. NifmServiceType_NotInitialized = 0, ///< Initializes nifm:u.
@ -35,18 +35,27 @@ typedef enum {
*/ */
void nifmSetServiceType(NifmServiceType serviceType); void nifmSetServiceType(NifmServiceType serviceType);
/// Initialize nifm. This is used automatically by \ref socketInitialize.
Result nifmInitialize(void); Result nifmInitialize(void);
/// Exit nifm. This is used automatically by \ref socketExit.
void nifmExit(void); void nifmExit(void);
Result nifmGetCurrentIpAddress(u32* out); /// Gets the Service object for the actual nifm:* service session.
Service* nifmGetServiceSession_StaticService(void);
Result nifmIsWirelessCommunicationEnabled(bool* out); /// Gets the Service object for IGeneralService.
Service* nifmGetServiceSession_GeneralService(void);
Result nifmGetCurrentIpAddress(u32* out);
/** /**
* @note Works only if called from nifm:a or nifm:s. * @note Works only if called from nifm:a or nifm:s.
*/ */
Result nifmSetWirelessCommunicationEnabled(bool enable); Result nifmSetWirelessCommunicationEnabled(bool enable);
Result nifmIsWirelessCommunicationEnabled(bool* out);
/** /**
* @note Will fail with 0xd46ed if Internet is neither connecting or connected (airplane mode or no known network in reach). * @note Will fail with 0xd46ed if Internet is neither connecting or connected (airplane mode or no known network in reach).
* @param wifiStrength Strength of the Wi-Fi signal in number of bars from 0 to 3. * @param wifiStrength Strength of the Wi-Fi signal in number of bars from 0 to 3.

View File

@ -1,101 +1,527 @@
/** /**
* @file ns.h * @file ns.h
* @brief NS service IPC wrapper. * @brief NS services IPC wrapper.
* @author yellows8 * @author yellows8
* @copyright libnx Authors * @copyright libnx Authors
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../nacp.h" #include "../nacp.h"
#include "../sf/service.h"
#include "../services/fs.h" #include "../services/fs.h"
#include "../services/ncm.h"
#include "../services/async.h"
#include "../kernel/event.h" #include "../kernel/event.h"
#include "../kernel/tmem.h"
typedef struct { /// ShellEvent
NacpStruct nacp;
u8 icon[0x20000];//JPEG
} NsApplicationControlData;
typedef struct
{
u8 title_type;
u8 storageID;
u8 unk_x02;
u8 padding;
u32 title_version;
u64 titleID;
} NsApplicationContentMetaStatus;
typedef struct
{
u64 titleID;
u8 type;
u8 unk_x09;
u8 unk_x0A[6];
u8 unk_x10;
u8 unk_x11[7];
} NsApplicationRecord;
typedef struct {
u64 titleID;
u32 version;
u8 storageID;
u8 index;
u8 is_application;
} NsLaunchProperties;
typedef enum { typedef enum {
NsShellEvent_None = 0, NsShellEvent_None = 0, ///< None
NsShellEvent_Exit = 1, NsShellEvent_Exit = 1, ///< Exit
NsShellEvent_Start = 2, NsShellEvent_Start = 2, ///< Start
NsShellEvent_Crash = 3, NsShellEvent_Crash = 3, ///< Crash
NsShellEvent_Debug = 4, NsShellEvent_Debug = 4, ///< Debug
} NsShellEvent; } NsShellEvent;
/// ApplicationControlSource
typedef enum {
NsApplicationControlSource_CacheOnly = 0, ///< Returns data from cache.
NsApplicationControlSource_Storage = 1, ///< Returns data from storage if not present in cache.
NsApplicationControlSource_StorageOnly = 2, ///< Returns data from storage without using cache.
} NsApplicationControlSource;
/// BackgroundNetworkUpdateState
typedef enum {
NsBackgroundNetworkUpdateState_None = 0, ///< No sysupdate task exists.
NsBackgroundNetworkUpdateState_Downloading = 1, ///< Sysupdate download in progress.
NsBackgroundNetworkUpdateState_Ready = 2, ///< Sysupdate ready, pending install.
} NsBackgroundNetworkUpdateState;
/// LatestSystemUpdate
typedef enum {
NsLatestSystemUpdate_Unknown0 = 0, ///< Unknown.
NsLatestSystemUpdate_Unknown1 = 1, ///< Unknown.
NsLatestSystemUpdate_Unknown2 = 2, ///< Unknown.
} NsLatestSystemUpdate;
/// SystemUpdateControl
typedef struct { typedef struct {
NsShellEvent event; Service s; ///< ISystemUpdateControl
u64 process_id; TransferMemory tmem; ///< TransferMemory for SetupCardUpdate/SetupCardUpdateViaSystemUpdater.
} NsSystemUpdateControl;
/// ApplicationControlData
typedef struct {
NacpStruct nacp; ///< \ref NacpStruct
u8 icon[0x20000]; ///< JPEG
} NsApplicationControlData;
/// NsApplicationContentMetaStatus
typedef struct {
u8 title_type; ///< \ref NcmContentMetaType
u8 storageID; ///< \ref FsStorageId
u8 unk_x02; ///< Unknown.
u8 padding; ///< Padding.
u32 title_version; ///< Title version.
u64 titleID; ///< titleID.
} NsApplicationContentMetaStatus;
/// ApplicationRecord
typedef struct {
u64 titleID; ///< titleID.
u8 type; ///< Type.
u8 unk_x09; ///< Unknown.
u8 unk_x0A[6]; ///< Unknown.
u8 unk_x10; ///< Unknown.
u8 unk_x11[7]; ///< Unknown.
} NsApplicationRecord;
/// LaunchProperties
typedef struct {
u64 titleID; ///< titleID.
u32 version; ///< Title version.
u8 storageID; ///< \ref FsStorageId
u8 index; ///< Index.
u8 is_application; ///< Whether this is an Application.
} NsLaunchProperties;
/// ShellEventInfo
typedef struct {
NsShellEvent event; ///< \ref NsShellEvent
u64 process_id; ///< processID.
} NsShellEventInfo; } NsShellEventInfo;
/// SystemUpdateProgress. Commands which have this as output will return 0 with the output cleared, when no task is available.
typedef struct {
s64 current_size; ///< Current size. This value can be larger than total_size when the async operation is finishing. When total_size is <=0, this current_size field may contain a progress value for when the total_size is not yet determined.
s64 total_size; ///< Total size, this field is only valid when >0.
} NsSystemUpdateProgress;
/// EulaDataPath
typedef struct {
char path[0x100]; ///< Path.
} NsEulaDataPath;
/// SystemDeliveryInfo
typedef struct {
u32 protocol_version; ///< Must be <= to and match a system-setting.
u8 unk_x4[0x8]; ///< Unused by \ref nssuRequestSendSystemUpdate / \ref nssuControlRequestReceiveSystemUpdate, besides HMAC validation.
u32 systemupdate_meta_version; ///< SystemUpdate meta version.
u64 systemupdate_meta_titleid; ///< SystemUpdate meta titleID.
u8 unk_x18; ///< Copied into state by \ref nssuRequestSendSystemUpdate.
u8 unk_x19[0xc7]; ///< Unused by \ref nssuRequestSendSystemUpdate / \ref nssuControlRequestReceiveSystemUpdate, besides HMAC validation.
u8 hmac[0x20]; ///< HMAC-SHA256 over the previous 0xe0-bytes.
} NsSystemDeliveryInfo;
/// Default size for \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater. This is the size used by qlaunch for SetupCardUpdate.
#define NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT 0x100000
///@name ns
///@{
/// Initialize ns services. Uses ns:am on pre-3.0.0, ns:am2 on [3.0.0+].
Result nsInitialize(void); Result nsInitialize(void);
/// Exit ns services.
void nsExit(void); void nsExit(void);
Result nsListApplicationRecord(NsApplicationRecord* buffer, size_t size, size_t entry_offset, size_t* out_entrycount); /// Gets the Service object for the actual ns:* service session. Only initialized on [3.0.0+], on pre-3.0.0 see \ref nsGetServiceSession_ApplicationManagerInterface.
Result nsListApplicationContentMetaStatus(u64 titleID, u32 index, NsApplicationContentMetaStatus* buffer, size_t size, size_t* out_entrycount); Service* nsGetServiceSession_GetterInterface(void);
Result nsGetApplicationControlData(u8 flag, u64 titleID, NsApplicationControlData* buffer, size_t size, size_t* actual_size);
/// Gets the Service object for IApplicationManagerInterface.
Service* nsGetServiceSession_ApplicationManagerInterface(void);
/**
* @brief Gets an listing of \ref NsApplicationRecord.
* @param[out] records Output array of \ref NsApplicationRecord.
* @param[in] count Size of the records array in entries.
* @param[in] entry_offset Starting entry offset.
* @param[out] out_entrycount Total output entries.
*/
Result nsListApplicationRecord(NsApplicationRecord* records, s32 count, s32 entry_offset, s32* out_entrycount);
/**
* @brief Gets an listing of \ref NsApplicationContentMetaStatus.
* @param[in] titleID titleID.
* @param[in] index Starting entry index.
* @param[out] list Output array of \ref NsApplicationContentMetaStatus.
* @param[in] count Size of the list array in entries.
* @param[out] out_entrycount Total output entries.
*/
Result nsListApplicationContentMetaStatus(u64 titleID, s32 index, NsApplicationContentMetaStatus* list, s32 count, s32* out_entrycount);
/**
* @brief Gets the \ref NsApplicationControlData for the specified title.
* @param[in] flag Flag, official sw uses value 1.
* @param[in] titleID titleID.
* @param[out] buffer \ref NsApplicationControlData
* @param[in] size Size of the buffer.
* @param[out] actual_size Actual output size.
*/
Result nsGetApplicationControlData(NsApplicationControlSource source, u64 titleID, NsApplicationControlData* buffer, size_t size, u64* actual_size);
/** /**
* @brief Returns the total storage capacity (used + free) from content manager services. * @brief Returns the total storage capacity (used + free) from content manager services.
* @param storage_id Specified FsStorageId. (Must be FsStorageId_SdCard) * @param[in] storage_id Specified FsStorageId. (Must be FsStorageId_SdCard)
* @param size Pointer to output the total storage size to. * @param[out] size Pointer to output the total storage size to.
*/ */
Result nsGetTotalSpaceSize(FsStorageId storage_id, u64 *size); Result nsGetTotalSpaceSize(FsStorageId storage_id, u64 *size);
/** /**
* @brief Returns the available storage capacity from content manager services. * @brief Returns the available storage capacity from content manager services.
* @param storage_id Specified FsStorageId. (Must be FsStorageId_SdCard) * @param[in] storage_id Specified FsStorageId. (Must be FsStorageId_SdCard)
* @param size Pointer to output the free storage size to. * @param[out] size Pointer to output the free storage size to.
*/ */
Result nsGetFreeSpaceSize(FsStorageId storage_id, u64 *size); Result nsGetFreeSpaceSize(FsStorageId storage_id, u64 *size);
///@}
///@name ns:vm
///@{
/// Initialize ns:vm. On pre-3.0.0 this must be used with \ref nsInitialize.
Result nsvmInitialize(void); Result nsvmInitialize(void);
/// Exit ns:vm.
void nsvmExit(void); void nsvmExit(void);
Result nsvmNeedsUpdateVulnerability(bool *out); /// Gets the Service object for ns:vm. This is only initialized on [3.0.0+].
Result nsvmGetSafeSystemVersion(u16 *out); Service* nsvmGetServiceSession(void);
/* ns:dev */ Result nsvmNeedsUpdateVulnerability(bool *out);
Result nsvmGetSafeSystemVersion(NcmContentMetaKey *out); ///< [4.0.0+]
///@}
///@name ns:dev
///@{
/// Initialize ns:dev.
Result nsdevInitialize(void); Result nsdevInitialize(void);
/// Initialize ns:dev.
void nsdevExit(void); 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);
Result nsdevTerminateProcess(u64 pid); Result nsdevTerminateProcess(u64 pid);
Result nsdevTerminateProgram(u64 tid); Result nsdevTerminateProgram(u64 tid);
Result nsdevGetShellEvent(Event* out); // Autoclear for nsdevShellEvent is always true. Result nsdevGetShellEvent(Event* out_event); ///< Autoclear for nsdevShellEvent is always true.
Result nsdevGetShellEventInfo(NsShellEventInfo* out); Result nsdevGetShellEventInfo(NsShellEventInfo* out);
Result nsdevTerminateApplication(void); Result nsdevTerminateApplication(void);
Result nsdevPrepareLaunchProgramFromHost(NsLaunchProperties* out, const char* path, size_t path_len); Result nsdevPrepareLaunchProgramFromHost(NsLaunchProperties* out, const char* path, size_t path_len);
Result nsdevLaunchApplication(u64* out_pid, u64 app_title_id, u32 flags); Result nsdevLaunchApplicationForDevelop(u64* out_pid, u64 app_title_id, u32 flags);
Result nsdevLaunchApplicationWithStorageId(u64* out_pid, u64 app_title_id, u32 flags, u8 app_storage_id, u8 patch_storage_id); Result nsdevLaunchApplicationWithStorageIdForDevelop(u64* out_pid, u64 app_title_id, u32 flags, u8 app_storage_id, u8 patch_storage_id);
Result nsdevIsSystemMemoryResourceLimitBoosted(bool* out); Result nsdevIsSystemMemoryResourceLimitBoosted(bool* out); ///< [6.0.0-8.1.0]
Result nsdevGetRunningApplicationProcessId(u64* out_pid); Result nsdevGetRunningApplicationProcessIdForDevelop(u64* out_pid); ///< [6.0.0+]
Result nsdevSetCurrentApplicationRightsEnvironmentCanBeActive(bool can_be_active); Result nsdevSetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop(bool can_be_active); ///< [6.0.0+]
///@}
///@name ns:su
///@{
/// Initialize ns:su.
Result nssuInitialize(void);
/// Exit ns:su.
void nssuExit(void);
/// Gets the Service object for ns:su.
Service* nssuGetServiceSession(void);
/**
* @brief Gets the \ref NsBackgroundNetworkUpdateState.
* @note Internally this uses nim commands ListSystemUpdateTask and GetSystemUpdateTaskInfo to determine the output state.
* @param[out] out \ref NsBackgroundNetworkUpdateState
*/
Result nssuGetBackgroundNetworkUpdateState(NsBackgroundNetworkUpdateState *out);
/**
* @brief Opens a \ref NsSystemUpdateControl.
* @note Only 1 \ref NsSystemUpdateControl can be open at a time.
* @param[out] c \ref NsSystemUpdateControl
*/
Result nssuOpenSystemUpdateControl(NsSystemUpdateControl *c);
/**
* @brief Uses nim ListSystemUpdateTask, then uses the task with DestroySystemUpdateTask if it exists. Then this runs ExFat handling, updates state, and sets the same state flag as \ref nssuRequestBackgroundNetworkUpdate.
* @note Only usable when a \ref NsSystemUpdateControl isn't open.
*/
Result nssuNotifyExFatDriverRequired(void);
/**
* @brief ClearExFatDriverStatusForDebug
*/
Result nssuClearExFatDriverStatusForDebug(void);
/**
* @brief RequestBackgroundNetworkUpdate
* @note Only usable when a \ref NsSystemUpdateControl isn't open.
*/
Result nssuRequestBackgroundNetworkUpdate(void);
/**
* @brief This checks whether a sysupdate is needed with the input \ref NcmContentMetaKey using NCM commands, if not this will just return 0. Otherwise, this will then run code which is identical to \ref nssuRequestBackgroundNetworkUpdate.
* @note Only usable when a \ref NsSystemUpdateControl isn't open.
* @param[in] key \ref NcmContentMetaKey
*/
Result nssuNotifyBackgroundNetworkUpdate(const NcmContentMetaKey *key);
/**
* @brief NotifyExFatDriverDownloadedForDebug
*/
Result nssuNotifyExFatDriverDownloadedForDebug(void);
/**
* @brief Gets an Event which can be signaled by \ref nssuNotifySystemUpdateForContentDelivery.
* @note The Event must be closed by the user once finished with it.
* @param[out] out_event Output Event with autoclear=false.
*/
Result nssuGetSystemUpdateNotificationEventForContentDelivery(Event* out_event);
/**
* @brief Signals the event returned by \ref nssuGetSystemUpdateNotificationEventForContentDelivery.
*/
Result nssuNotifySystemUpdateForContentDelivery(void);
/**
* @brief This does shutdown preparation.
* @note This is used by am-sysmodule, so generally there's no need to use this.
* @note Only available on [3.0.0+].
*/
Result nssuPrepareShutdown(void);
/**
* @brief This uses nim ListSystemUpdateTask, then when a task is returned uses it with DestroySystemUpdateTask.
* @note Only available on [4.0.0+].
*/
Result nssuDestroySystemUpdateTask(void);
/**
* @brief RequestSendSystemUpdate
* @note Only available on [4.0.0+].
* @param[out] a \ref AsyncResult
* @param[in] inval0 Unknown input value.
* @param[in] inval1 Unknown input value. qlaunch uses value 0xD904 (55556).
* @param[in] info \ref NsSystemDeliveryInfo
*/
Result nssuRequestSendSystemUpdate(AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info);
/**
* @brief GetSendSystemUpdateProgress
* @note Only available on [4.0.0+].
* @param[out] out \ref NsSystemUpdateProgress
*/
Result nssuGetSendSystemUpdateProgress(NsSystemUpdateProgress *out);
///@}
///@name ISystemUpdateControl
///@{
/**
* @brief Close a \ref NsSystemUpdateControl.
* @param c \ref NsSystemUpdateControl
*/
void nssuControlClose(NsSystemUpdateControl *c);
/**
* @brief Gets whether a network sysupdate was downloaded, with install pending.
* @param c \ref NsSystemUpdateControl
* @param[out] out Output flag.
*/
Result nssuControlHasDownloaded(NsSystemUpdateControl *c, bool* out);
/**
* @brief RequestCheckLatestUpdate
* @param c \ref NsSystemUpdateControl
* @param[out] a \ref AsyncValue. The data that can be read from this is u8 \ref NsLatestSystemUpdate.
*/
Result nssuControlRequestCheckLatestUpdate(NsSystemUpdateControl *c, AsyncValue *a);
/**
* @brief RequestDownloadLatestUpdate
* @param c \ref NsSystemUpdateControl
* @param[out] a \ref AsyncResult
*/
Result nssuControlRequestDownloadLatestUpdate(NsSystemUpdateControl *c, AsyncResult *a);
/**
* @brief GetDownloadProgress
* @param c \ref NsSystemUpdateControl
* @param[out] out \ref NsSystemUpdateProgress
*/
Result nssuControlGetDownloadProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out);
/**
* @brief ApplyDownloadedUpdate
* @param c \ref NsSystemUpdateControl
*/
Result nssuControlApplyDownloadedUpdate(NsSystemUpdateControl *c);
/**
* @brief RequestPrepareCardUpdate
* @param c \ref NsSystemUpdateControl
* @param[out] a \ref AsyncResult
*/
Result nssuControlRequestPrepareCardUpdate(NsSystemUpdateControl *c, AsyncResult *a);
/**
* @brief GetPrepareCardUpdateProgress
* @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this.
* @param c \ref NsSystemUpdateControl
* @param[out] out \ref NsSystemUpdateProgress
*/
Result nssuControlGetPrepareCardUpdateProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out);
/**
* @brief HasPreparedCardUpdate
* @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this.
* @param c \ref NsSystemUpdateControl
* @param[out] out Output flag.
*/
Result nssuControlHasPreparedCardUpdate(NsSystemUpdateControl *c, bool* out);
/**
* @brief ApplyCardUpdate
* @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this.
* @param c \ref NsSystemUpdateControl
*/
Result nssuControlApplyCardUpdate(NsSystemUpdateControl *c);
/**
* @brief Gets the filesize for the specified DownloadedEulaData.
* @note This mounts the Eula title, then uses the file "<mountname>:/<input path>".
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[out] filesize Output filesize.
*/
Result nssuControlGetDownloadedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize);
/**
* @brief Gets the specified DownloadedEulaData.
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[out] buffer Output buffer.
* @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetDownloadedEulaDataSize.
* @param[out] filesize Output filesize.
*/
Result nssuControlGetDownloadedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize);
/**
* @brief SetupCardUpdate
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[in] buffer TransferMemory buffer, when NULL this is automatically allocated.
* @param[in] size TransferMemory buffer size, see \ref NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT.
*/
Result nssuControlSetupCardUpdate(NsSystemUpdateControl *c, void* buffer, size_t size);
/**
* @brief Gets the filesize for the specified PreparedCardUpdateEulaData.
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[out] filesize Output filesize.
*/
Result nssuControlGetPreparedCardUpdateEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize);
/**
* @brief Gets the specified PreparedCardUpdateEulaData.
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[out] buffer Output buffer.
* @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetPreparedCardUpdateEulaDataSize.
* @param[out] filesize Output filesize.
*/
Result nssuControlGetPreparedCardUpdateEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize);
/**
* @brief SetupCardUpdateViaSystemUpdater
* @note Same as \ref nssuControlSetupCardUpdate, except this doesn't run the code for fs cmds GetGameCardHandle/GetGameCardUpdatePartitionInfo, and uses fs OpenRegisteredUpdatePartition instead of OpenGameCardFileSystem.
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[in] buffer TransferMemory buffer, when NULL this is automatically allocated.
* @param[in] size TransferMemory buffer size, see \ref NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT.
*/
Result nssuControlSetupCardUpdateViaSystemUpdater(NsSystemUpdateControl *c, void* buffer, size_t size);
/**
* @brief HasReceived
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
* @param[out] out Output flag.
*/
Result nssuControlHasReceived(NsSystemUpdateControl *c, bool* out);
/**
* @brief RequestReceiveSystemUpdate
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
* @param[out] a \ref AsyncResult
* @param[in] inval0 Unknown input value.
* @param[in] inval1 Unknown input value. qlaunch uses value 0xD904 (55556).
* @param[in] info \ref NsSystemDeliveryInfo
*/
Result nssuControlRequestReceiveSystemUpdate(NsSystemUpdateControl *c, AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info);
/**
* @brief GetReceiveProgress
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
* @param[out] out \ref NsSystemUpdateProgress
*/
Result nssuControlGetReceiveProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out);
/**
* @brief ApplyReceivedUpdate
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
*/
Result nssuControlApplyReceivedUpdate(NsSystemUpdateControl *c);
/**
* @brief Gets the filesize for the specified ReceivedEulaData.
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[out] filesize Output filesize.
*/
Result nssuControlGetReceivedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize);
/**
* @brief Gets the specified ReceivedEulaData.
* @note See the note for \ref nssuControlGetDownloadedEulaDataSize.
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
* @param[in] path EulaData path.
* @param[out] buffer Output buffer.
* @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetReceivedEulaDataSize.
* @param[out] filesize Output filesize.
*/
Result nssuControlGetReceivedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize);
/**
* @brief Does setup for ReceiveSystemUpdate by using the same nim cmds as \ref nssuDestroySystemUpdateTask.
* @note Only available on [4.0.0+].
* @param c \ref NsSystemUpdateControl
*/
Result nssuControlSetupToReceiveSystemUpdate(NsSystemUpdateControl *c);
/**
* @brief RequestCheckLatestUpdateIncludesRebootlessUpdate
* @note Only available on [6.0.0+].
* @param c \ref NsSystemUpdateControl
* @param[out] a \ref AsyncValue
*/
Result nssuControlRequestCheckLatestUpdateIncludesRebootlessUpdate(NsSystemUpdateControl *c, AsyncValue *a);
///@}

View File

@ -6,6 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../sf/service.h"
#include "../kernel/event.h" #include "../kernel/event.h"
Result nvInitialize(void); Result nvInitialize(void);

View File

@ -9,7 +9,7 @@
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../kernel/event.h" #include "../kernel/event.h"
#include "../services/sm.h" #include "../sf/service.h"
/// LaunchFlag /// LaunchFlag
typedef enum { typedef enum {
@ -79,10 +79,10 @@ Service* pmbmGetServiceSession(void);
Result pmdmntGetDebugProcesses(u32* out_count, u64* out_pids, size_t max_pids); Result pmdmntGetDebugProcesses(u32* out_count, u64* out_pids, size_t max_pids);
Result pmdmntStartProcess(u64 pid); Result pmdmntStartProcess(u64 pid);
Result pmdmntGetTitlePid(u64* pid_out, u64 title_id); Result pmdmntGetTitlePid(u64* pid_out, u64 title_id);
Result pmdmntEnableDebugForTitleId(Handle* handle_out, u64 title_id); Result pmdmntEnableDebugForTitleId(Event* out, u64 title_id);
Result pmdmntGetApplicationPid(u64* pid_out); Result pmdmntGetApplicationPid(u64* pid_out);
Result pmdmntEnableDebugForApplication(Handle* handle_out); Result pmdmntEnableDebugForApplication(Event* out);
Result pmdmntDisableDebug(void); Result pmdmntDisableDebug(u32 which);
Result pminfoGetTitleId(u64* title_id_out, u64 pid); Result pminfoGetTitleId(u64* title_id_out, u64 pid);

View File

@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
#include "../kernel/event.h" #include "../kernel/event.h"
typedef enum { typedef enum {

View File

@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
#include "../services/ldr.h" #include "../services/ldr.h"
Result ldrRoInitialize(void); Result ldrRoInitialize(void);

View File

@ -7,37 +7,39 @@
* @copyright libnx Authors * @copyright libnx Authors
*/ */
#pragma once #pragma once
#include "../result.h" #include "../types.h"
#include "../kernel/event.h" #include "../kernel/event.h"
#include "../services/sm.h" #include "../sf/service.h"
#define SET_MAX_NAME_SIZE 0x48 #define SET_MAX_NAME_SIZE 0x48
#define SET_MAX_NICKNAME_SIZE 0x80 #define SET_MAX_NICKNAME_SIZE 0x80
typedef enum { typedef enum {
ColorSetId_Light=0, ColorSetId_Light = 0,
ColorSetId_Dark=1 ColorSetId_Dark = 1,
} ColorSetId; } ColorSetId;
/// IDs for Language. /// IDs for Language.
typedef enum typedef enum
{ {
SetLanguage_JA = 0, ///< Japanese SetLanguage_JA = 0, ///< Japanese
SetLanguage_ENUS = 1, ///< US English ("AmericanEnglish") SetLanguage_ENUS = 1, ///< US English ("AmericanEnglish")
SetLanguage_FR = 2, ///< French SetLanguage_FR = 2, ///< French
SetLanguage_DE = 3, ///< German SetLanguage_DE = 3, ///< German
SetLanguage_IT = 4, ///< Italian SetLanguage_IT = 4, ///< Italian
SetLanguage_ES = 5, ///< Spanish SetLanguage_ES = 5, ///< Spanish
SetLanguage_ZHCN = 6, ///< Simplified Chinese ("Chinese") SetLanguage_ZHCN = 6, ///< Simplified Chinese ("Chinese")
SetLanguage_KO = 7, ///< Korean SetLanguage_KO = 7, ///< Korean
SetLanguage_NL = 8, ///< Dutch SetLanguage_NL = 8, ///< Dutch
SetLanguage_PT = 9, ///< Portuguese SetLanguage_PT = 9, ///< Portuguese
SetLanguage_RU = 10, ///< Russian SetLanguage_RU = 10, ///< Russian
SetLanguage_ZHTW = 11, ///< Traditional Chinese ("Taiwanese") SetLanguage_ZHTW = 11, ///< Traditional Chinese ("Taiwanese")
SetLanguage_ENGB = 12, ///< GB English ("BritishEnglish") SetLanguage_ENGB = 12, ///< GB English ("BritishEnglish")
SetLanguage_FRCA = 13, ///< CA French ("CanadianFrench") SetLanguage_FRCA = 13, ///< CA French ("CanadianFrench")
SetLanguage_ES419 = 14, ///< "LatinAmericanSpanish" SetLanguage_ES419 = 14, ///< "LatinAmericanSpanish"
SetLanguage_Total, ///< Total languages supported by this enum. SetLanguage_ZHHANS = 15, ///< [4.0.0+] ChineseSimplified
SetLanguage_ZHHANT = 16, ///< [4.0.0+] ChineseTraditional
SetLanguage_Total, ///< Total languages supported by this enum.
} SetLanguage; } SetLanguage;
/// Region codes. /// Region codes.
@ -46,27 +48,30 @@ typedef enum {
SetRegion_USA = 1, ///< The Americas SetRegion_USA = 1, ///< The Americas
SetRegion_EUR = 2, ///< Europe SetRegion_EUR = 2, ///< Europe
SetRegion_AUS = 3, ///< Australia/New Zealand SetRegion_AUS = 3, ///< Australia/New Zealand
SetRegion_CHN = 4, ///< China
SetRegion_KOR = 5, ///< Korea
SetRegion_TWN = 6, ///< Taiwan
} SetRegion; } SetRegion;
/// Command IDs for setsysGetFlag/setsysSetFlag. /// Command IDs for setsysGetFlag/setsysSetFlag.
typedef enum { typedef enum {
SetSysFlag_LockScreen = 7, SetSysFlag_LockScreen = 7,
SetSysFlag_ConsoleInformationUpload = 25, SetSysFlag_ConsoleInformationUpload = 25,
SetSysFlag_AutomaticApplicationDownload = 27, SetSysFlag_AutomaticApplicationDownload = 27,
SetSysFlag_Quest = 47, SetSysFlag_Quest = 47,
SetSysFlag_Usb30Enable = 65, SetSysFlag_Usb30Enable = 65,
SetSysFlag_NfcEnable = 69, SetSysFlag_NfcEnable = 69,
SetSysFlag_WirelessLanEnable = 73, SetSysFlag_WirelessLanEnable = 73,
SetSysFlag_BluetoothEnable = 88, SetSysFlag_BluetoothEnable = 88,
SetSysFlag_AutoUpdateEnable = 95, SetSysFlag_AutoUpdateEnable = 95, ///< [2.0.0+]
SetSysFlag_BatteryPercentage = 99, SetSysFlag_BatteryPercentage = 99, ///< [2.0.0+]
SetSysFlag_ExternalRtcReset = 101, SetSysFlag_ExternalRtcReset = 101, ///< [2.0.0+]
SetSysFlag_UsbFullKeyEnable = 103, SetSysFlag_UsbFullKeyEnable = 103, ///< [3.0.0+]
SetSysFlag_BluetoothAfhEnable = 111, SetSysFlag_BluetoothAfhEnable = 111, ///< [3.0.0+]
SetSysFlag_BluetoothBoostEnable = 113, SetSysFlag_BluetoothBoostEnable = 113, ///< [3.0.0+]
SetSysFlag_InRepairProcessEnable = 115, SetSysFlag_InRepairProcessEnable = 115, ///< [3.0.0+]
SetSysFlag_HeadphoneVolumeUpdate = 117, SetSysFlag_HeadphoneVolumeUpdate = 117, ///< [3.0.0+]
SetSysFlag_RequiresRunRepairTimeReviser = 141, SetSysFlag_RequiresRunRepairTimeReviser = 141, ///< [5.0.0+]
} SetSysFlag; } SetSysFlag;
/// Structure returned by \ref setsysGetFirmwareVersion /// Structure returned by \ref setsysGetFirmwareVersion
@ -89,11 +94,11 @@ Result setInitialize(void);
void setExit(void); void setExit(void);
Service* setGetServiceSession(void); Service* setGetServiceSession(void);
/// Converts LanguageCode to Language. /// Converts LanguageCode to \ref SetLanguage.
Result setMakeLanguage(u64 LanguageCode, s32 *Language); Result setMakeLanguage(u64 LanguageCode, SetLanguage *Language);
/// Converts Language to LanguageCode. /// Converts \ref SetLanguage to LanguageCode.
Result setMakeLanguageCode(s32 Language, u64 *LanguageCode); Result setMakeLanguageCode(SetLanguage Language, u64 *LanguageCode);
/// Gets the current system LanguageCode. /// Gets the current system LanguageCode.
/// Normally this should be used instead of \ref setGetLanguageCode. /// Normally this should be used instead of \ref setGetLanguageCode.
@ -138,8 +143,9 @@ Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u6
* @param item_key Item key string. * @param item_key Item key string.
* @param value_out Pointer to output the value to. * @param value_out Pointer to output the value to.
* @param value_out_size Size of the value_out buffer. * @param value_out_size Size of the value_out buffer.
* @param size_out Total size which was copied to value_out.
*/ */
Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size); Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size, u64 *size_out);
/** /**
* @brief Gets the system's serial number. * @brief Gets the system's serial number.
@ -169,9 +175,9 @@ Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out);
/** /**
* @brief Gets an event that settings will signal on flag change. * @brief Gets an event that settings will signal on flag change.
* @param out Event to bind. Output event will have autoclear=false. * @param out_event Event to bind. Output event will have autoclear=false.
*/ */
Result setsysBindFatalDirtyFlagEvent(Event *out); Result setsysBindFatalDirtyFlagEvent(Event *out_event);
/** /**
* @brief Gets the settings flags that have changed. * @brief Gets the settings flags that have changed.

View File

@ -9,67 +9,10 @@
#include "../types.h" #include "../types.h"
#include "../kernel/svc.h" #include "../kernel/svc.h"
#include "../kernel/ipc.h" #include "../kernel/ipc.h"
#include "../sf/service.h"
/// Service type. #pragma GCC diagnostic push
typedef enum { #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
ServiceType_Uninitialized, ///< Uninitialized service.
ServiceType_Normal, ///< Normal service.
ServiceType_Domain, ///< Domain.
ServiceType_DomainSubservice, ///< Domain subservice;
ServiceType_Override, ///< Service overriden in the homebrew environment.
} ServiceType;
/// Service object structure.
typedef struct {
Handle handle;
u32 object_id;
ServiceType type;
} Service;
/**
* @brief Returns whether a service is overriden in the homebrew environment.
* @param[in] s Service object.
* @return true if overriden.
*/
static inline bool serviceIsOverride(Service* s) {
return s->type == ServiceType_Override;
}
/**
* @brief Returns whether a service has been initialized.
* @param[in] s Service object.
* @return true if initialized.
*/
static inline bool serviceIsActive(Service* s) {
return s->type != ServiceType_Uninitialized;
}
/**
* @brief Returns whether a service is a domain.
* @param[in] s Service object.
* @return true if a domain.
*/
static inline bool serviceIsDomain(Service* s) {
return s->type == ServiceType_Domain;
}
/**
* @brief Returns whether a service is a domain subservice.
* @param[in] s Service object.
* @return true if a domain subservice.
*/
static inline bool serviceIsDomainSubservice(Service* s) {
return s->type == ServiceType_DomainSubservice;
}
/**
* @brief For a domain/domain subservice, return the associated object ID.
* @param[in] s Service object, necessarily a domain or domain subservice.
* @return The object ID.
*/
static inline u32 serviceGetObjectId(Service* s) {
return s->object_id;
}
/** /**
* @brief Closes a domain object by ID. * @brief Closes a domain object by ID.
@ -77,8 +20,9 @@ static inline u32 serviceGetObjectId(Service* s) {
* @param object_id ID of the object to close. * @param object_id ID of the object to close.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result serviceCloseObjectById(Service* s, u32 object_id) { static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
return ipcCloseObjectById(s->handle, object_id); return ipcCloseObjectById(s->session, object_id);
} }
/** /**
@ -86,31 +30,9 @@ static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
* @param[in] s Service object. * @param[in] s Service object.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result serviceIpcDispatch(Service* s) { static inline Result serviceIpcDispatch(Service* s) {
return ipcDispatch(s->handle); return ipcDispatch(s->session);
}
/**
* @brief Creates a service object from an IPC session handle.
* @param[out] s Service object.
* @param[in] h IPC session handle.
*/
static inline void serviceCreate(Service* s, Handle h) {
s->handle = h;
s->type = ServiceType_Normal;
s->object_id = IPC_INVALID_OBJECT_ID;
}
/**
* @brief Creates a domain subservice object from a parent service.
* @param[out] s Service object.
* @param[in] parent Parent service, necessarily a domain or domain subservice.
* @param[in] object_id Object ID for this subservice.
*/
static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id) {
s->handle = parent->handle;
s->type = ServiceType_DomainSubservice;
s->object_id = object_id;
} }
/** /**
@ -120,6 +42,7 @@ static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u3
* @param[in] r Parsed IPC command containing handles/object IDs to create subservice from. * @param[in] r Parsed IPC command containing handles/object IDs to create subservice from.
* @param[in] i The index of the handle/object ID to create subservice from. * @param[in] i The index of the handle/object ID to create subservice from.
*/ */
DEPRECATED
static inline void serviceCreateSubservice(Service* s, Service* parent, IpcParsedCommand* r, int i) { static inline void serviceCreateSubservice(Service* s, Service* parent, IpcParsedCommand* r, int i) {
if (r->IsDomainResponse) { if (r->IsDomainResponse) {
return serviceCreateDomainSubservice(s, parent, r->OutObjectIds[i]); return serviceCreateDomainSubservice(s, parent, r->OutObjectIds[i]);
@ -133,63 +56,13 @@ static inline void serviceCreateSubservice(Service* s, Service* parent, IpcParse
* @param[in] s Service object to send. * @param[in] s Service object to send.
* @param[in] cmd IPC command structure. * @param[in] cmd IPC command structure.
*/ */
DEPRECATED
static inline void serviceSendObject(Service* s, IpcCommand* cmd) { static inline void serviceSendObject(Service* s, IpcCommand* cmd) {
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) { if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
ipcSendObjectId(cmd, s->object_id); ipcSendObjectId(cmd, s->object_id);
} }
} }
/**
* @brief Converts a regular service to a domain.
* @param[in] s Service object.
* @return Result code.
*/
static inline Result serviceConvertToDomain(Service* s) {
Result rc = 0;
if (serviceIsOverride(s)) {
rc = ipcCloneSession(s->handle, 1, &s->handle);
if (R_FAILED(rc)) {
return rc;
}
s->type = ServiceType_Normal;
}
rc = ipcConvertSessionToDomain(s->handle, &s->object_id);
if (R_SUCCEEDED(rc)) {
s->type = ServiceType_Domain;
}
return rc;
}
/**
* @brief Closes a service.
* @param[in] s Service object.
*/
static inline void serviceClose(Service* s) {
switch (s->type) {
case ServiceType_Normal:
case ServiceType_Domain:
ipcCloseSession(s->handle);
svcCloseHandle(s->handle);
break;
case ServiceType_DomainSubservice:
serviceCloseObjectById(s, s->object_id);
break;
case ServiceType_Override:
// Don't close because we don't own the overridden handle.
break;
case ServiceType_Uninitialized:
break;
}
s->type = ServiceType_Uninitialized;
}
/** /**
* @brief Prepares the header of an IPC command structure for a service. * @brief Prepares the header of an IPC command structure for a service.
* @param s Service to prepare message header for * @param s Service to prepare message header for
@ -197,6 +70,7 @@ static inline void serviceClose(Service* s) {
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request * @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
* @return Pointer to the raw embedded data structure in the request, ready to be filled out. * @return Pointer to the raw embedded data structure in the request, ready to be filled out.
*/ */
DEPRECATED
static inline void* serviceIpcPrepareHeader(Service* s, IpcCommand* cmd, size_t sizeof_raw) { static inline void* serviceIpcPrepareHeader(Service* s, IpcCommand* cmd, size_t sizeof_raw) {
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) { if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
return ipcPrepareHeaderForDomain(cmd, sizeof_raw, serviceGetObjectId(s)); return ipcPrepareHeaderForDomain(cmd, sizeof_raw, serviceGetObjectId(s));
@ -212,6 +86,7 @@ static inline void* serviceIpcPrepareHeader(Service* s, IpcCommand* cmd, size_t
* @param sizeof_raw Size in bytes of the raw data structure. * @param sizeof_raw Size in bytes of the raw data structure.
* @return Result code. * @return Result code.
*/ */
DEPRECATED
static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t sizeof_raw) { static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t sizeof_raw) {
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) { if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
return ipcParseDomainResponse(r, sizeof_raw); return ipcParseDomainResponse(r, sizeof_raw);
@ -220,6 +95,8 @@ static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t siz
} }
} }
#pragma GCC diagnostic pop
/** /**
* @brief Initializes SM. * @brief Initializes SM.
* @return Result code. * @return Result code.
@ -274,12 +151,6 @@ Result smRegisterService(Handle* handle_out, const char* name, bool is_light, in
*/ */
Result smUnregisterService(const char* name); Result smUnregisterService(const char* name);
/**
* @brief Check whether SM is initialized.
* @return true if initialized.
*/
bool smHasInitialized(void);
/** /**
* @brief Gets the Service session used to communicate with SM. * @brief Gets the Service session used to communicate with SM.
* @return Pointer to service session used to communicate with SM. * @return Pointer to service session used to communicate with SM.
@ -291,7 +162,13 @@ Service *smGetServiceSession(void);
* @param[in] name Name of the service. * @param[in] name Name of the service.
* @return Encoded name. * @return Encoded name.
*/ */
u64 smEncodeName(const char* name); NX_CONSTEXPR u64 smEncodeName(const char* name)
{
u64 name_encoded = 0;
for (unsigned i = 0; name[i] && i < 8; i ++)
name_encoded |= ((u64) name[i]) << (8*i);
return name_encoded;
}
/** /**
* @brief Overrides a service with a custom IPC service handle. * @brief Overrides a service with a custom IPC service handle.

View File

@ -6,6 +6,7 @@
*/ */
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../kernel/event.h"
#define SPL_RSA_BUFFER_SIZE (0x100) #define SPL_RSA_BUFFER_SIZE (0x100)
@ -74,7 +75,7 @@ Result splCryptoCryptAesCtr(const void *input, void *output, size_t size, u32 ke
Result splCryptoComputeCmac(const void *input, size_t size, u32 keyslot, void *out_cmac); Result splCryptoComputeCmac(const void *input, size_t size, u32 keyslot, void *out_cmac);
Result splCryptoLockAesEngine(u32 *out_keyslot); Result splCryptoLockAesEngine(u32 *out_keyslot);
Result splCryptoUnlockAesEngine(u32 keyslot); Result splCryptoUnlockAesEngine(u32 keyslot);
Result splCryptoGetSecurityEngineEvent(Handle *out_event); Result splCryptoGetSecurityEngineEvent(Event *out_event);
Result splRsaDecryptPrivateKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version, void *dst, size_t dst_size); Result splRsaDecryptPrivateKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version, void *dst, size_t dst_size);
@ -86,6 +87,8 @@ Result splEsUnwrapRsaOaepWrappedTitlekey(const void *rsa_wrapped_titlekey, const
Result splEsUnwrapAesWrappedTitlekey(const void *aes_wrapped_titlekey, u32 key_generation, void *out_sealed_titlekey); Result splEsUnwrapAesWrappedTitlekey(const void *aes_wrapped_titlekey, u32 key_generation, void *out_sealed_titlekey);
Result splEsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version); Result splEsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version);
Result splEsSecureExpMod(const void *input, const void *modulus, void *dst); Result splEsSecureExpMod(const void *input, const void *modulus, void *dst);
Result splEsUnwrapElicenseKey(const void *rsa_wrapped_elicense_key, const void *modulus, const void *label_hash, size_t label_hash_size, u32 key_generation, void *out_sealed_elicense_key);
Result splEsLoadElicenseKey(const void *sealed_elicense_key, u32 keyslot);
Result splFsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version); Result splFsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version);
Result splFsSecureExpMod(const void *input, const void *modulus, void *dst); Result splFsSecureExpMod(const void *input, const void *modulus, void *dst);

View File

@ -7,7 +7,7 @@
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
/// Time clock type. /// Time clock type.
typedef enum { typedef enum {
@ -28,11 +28,11 @@ typedef struct {
} TimeCalendarTime; } TimeCalendarTime;
typedef struct { typedef struct {
u32 wday; ///< 0-based day-of-week. u32 wday; ///< 0-based day-of-week.
u32 yday; ///< 0-based day-of-year. u32 yday; ///< 0-based day-of-year.
char timezoneName[8]; ///< Timezone name string. char timezoneName[8]; ///< Timezone name string.
u32 DST; ///< 0 = no DST, 1 = DST. u32 DST; ///< 0 = no DST, 1 = DST.
s32 offset; ///< Seconds relative to UTC for this timezone. s32 offset; ///< Seconds relative to UTC for this timezone.
} TimeCalendarAdditionalInfo; } TimeCalendarAdditionalInfo;
typedef struct { typedef struct {
@ -43,11 +43,27 @@ typedef struct {
char name[0x24]; char name[0x24];
} TimeLocationName; } TimeLocationName;
/// Initialize time. Used automatically during app startup.
Result timeInitialize(void); Result timeInitialize(void);
/// Exit time. Used automatically during app startup.
void timeExit(void); void timeExit(void);
/// Gets the Service object for the actual time service session.
Service* timeGetServiceSession(void); 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 ITimeZoneService.
Service* timeGetServiceSession_TimeZoneService(void);
/**
* @brief Gets the time for the specified clock.
* @param[in] type Clock to use.
* @param[out] timestamp POSIX UTC timestamp.
* @return Result code.
*/
Result timeGetCurrentTime(TimeType type, u64 *timestamp); Result timeGetCurrentTime(TimeType type, u64 *timestamp);
/** /**
@ -60,13 +76,13 @@ Result timeSetCurrentTime(TimeType type, u64 timestamp);
Result timeGetDeviceLocationName(TimeLocationName *name); Result timeGetDeviceLocationName(TimeLocationName *name);
Result timeSetDeviceLocationName(const TimeLocationName *name); Result timeSetDeviceLocationName(const TimeLocationName *name);
Result timeGetTotalLocationNameCount(u32 *total_location_name_count); Result timeGetTotalLocationNameCount(s32 *total_location_name_count);
Result timeLoadLocationNameList(u32 index, TimeLocationName *location_name_array, size_t location_name_size, u32 *location_name_count); Result timeLoadLocationNameList(s32 index, TimeLocationName *location_name_array, s32 location_name_max, s32 *location_name_count);
Result timeLoadTimeZoneRule(const TimeLocationName *name, TimeZoneRule *rule); Result timeLoadTimeZoneRule(const TimeLocationName *name, TimeZoneRule *rule);
Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count);
Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count);
Result timeToCalendarTime(const TimeZoneRule *rule, u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info); Result timeToCalendarTime(const TimeZoneRule *rule, u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info);
Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info); Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info);
Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count);
Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count);

View File

@ -0,0 +1,47 @@
/**
* @file ts.h
* @brief Temperature measurement (ts) service IPC wrapper.
* @author yellows8
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
/// Location
typedef enum {
TsLocation_Internal = 0, ///< Internal
TsLocation_External = 1, ///< External
} TsLocation;
/// Initialize ts.
Result tsInitialize(void);
/// Exit ts.
void tsExit(void);
/// Gets the Service for ts.
Service* tsGetServiceSession(void);
/**
* @brief Gets the min/max temperature for the specified \ref TsLocation.
* @param[in] location \ref TsLocation
* @param[out] min_temperature Output minimum temperature in Celsius.
* @param[out] max_temperature Output maximum temperature in Celsius.
*/
Result tsGetTemperatureRange(TsLocation location, s32 *min_temperature, s32 *max_temperature);
/**
* @brief Gets the temperature for the specified \ref TsLocation.
* @param[in] location \ref TsLocation
* @param[out] temperature Output temperature in Celsius.
*/
Result tsGetTemperature(TsLocation location, s32 *temperature);
/**
* @brief Gets the temperature for the specified \ref TsLocation, in MilliC.
* @param[in] location \ref TsLocation
* @param[out] temperature Output temperature in MilliC.
*/
Result tsGetTemperatureMilliC(TsLocation location, s32 *temperature);

View File

@ -96,7 +96,6 @@ typedef struct {
typedef struct { typedef struct {
Service s; Service s;
Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes. Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes.
size_t ptrbufsize; ///< [3.0.0+] IPC pointer buffer size.
struct usb_endpoint_descriptor desc; struct usb_endpoint_descriptor desc;
} UsbHsClientEpSession; } UsbHsClientEpSession;

View File

@ -1,13 +1,13 @@
/** /**
* @file wlaninf.h * @file wlaninf.h
* @brief WLAN InfraManager service IPC wrapper. * @brief WLAN InfraManager service IPC wrapper.
* @author natinusala * @author natinusala, yellows8
* @copyright libnx Authors * @copyright libnx Authors
*/ */
#pragma once #pragma once
#include "../kernel/ipc.h" #include "../types.h"
#include "../services/sm.h" #include "../sf/service.h"
/// WLAN State. /// WLAN State.
typedef enum { typedef enum {
@ -20,6 +20,7 @@ Result wlaninfInitialize(void);
void wlaninfExit(void); void wlaninfExit(void);
Service* wlaninfGetServiceSession(void); Service* wlaninfGetServiceSession(void);
/// Gets \ref WlanInfState.
Result wlaninfGetState(WlanInfState* out); Result wlaninfGetState(WlanInfState* out);
/// Value goes from -30 (really good signal) to -90 (barely enough to stay connected) /// Value goes from -30 (really good signal) to -90 (barely enough to stay connected)

370
nx/include/switch/sf/cmif.h Normal file
View File

@ -0,0 +1,370 @@
/**
* @file cmif.h
* @brief Common Message Interface Framework protocol
* @author fincs
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include "hipc.h"
#define CMIF_IN_HEADER_MAGIC 0x49434653 // "SFCI"
#define CMIF_OUT_HEADER_MAGIC 0x4F434653 // "SFCO"
typedef enum CmifCommandType {
CmifCommandType_Invalid = 0,
CmifCommandType_LegacyRequest = 1,
CmifCommandType_Close = 2,
CmifCommandType_LegacyControl = 3,
CmifCommandType_Request = 4,
CmifCommandType_Control = 5,
CmifCommandType_RequestWithContext = 6,
CmifCommandType_ControlWithContext = 7,
} CmifCommandType;
typedef enum CmifDomainRequestType {
CmifDomainRequestType_Invalid = 0,
CmifDomainRequestType_SendMessage = 1,
CmifDomainRequestType_Close = 2,
} CmifDomainRequestType;
typedef struct CmifInHeader {
u32 magic;
u32 version;
u32 command_id;
u32 token;
} CmifInHeader;
typedef struct CmifOutHeader {
u32 magic;
u32 version;
Result result;
u32 token;
} CmifOutHeader;
typedef struct CmifDomainInHeader {
u8 type;
u8 num_in_objects;
u16 data_size;
u32 object_id;
u32 padding;
u32 token;
} CmifDomainInHeader;
typedef struct CmifDomainOutHeader {
u32 num_out_objects;
u32 padding[3];
} CmifDomainOutHeader;
typedef struct CmifRequestFormat {
u32 object_id;
u32 request_id;
u32 context;
u32 data_size;
u32 server_pointer_size;
u32 num_in_auto_buffers;
u32 num_out_auto_buffers;
u32 num_in_buffers;
u32 num_out_buffers;
u32 num_inout_buffers;
u32 num_in_pointers;
u32 num_out_pointers;
u32 num_out_fixed_pointers;
u32 num_objects;
u32 num_handles;
u32 send_pid;
} CmifRequestFormat;
typedef struct CmifRequest {
HipcRequest hipc;
void* data;
u16* out_pointer_sizes;
u32* objects;
u32 server_pointer_size;
u32 cur_in_ptr_id;
} CmifRequest;
typedef struct CmifResponse {
void* data;
u32* objects;
Handle* copy_handles;
Handle* move_handles;
} CmifResponse;
NX_CONSTEXPR void* cmifGetAlignedDataStart(u32* data_words, void* base)
{
intptr_t data_start = ((u8*)data_words - (u8*)base + 15) &~ 15;
return (u8*)base + data_start;
}
NX_CONSTEXPR CmifRequest cmifMakeRequest(void* base, CmifRequestFormat fmt)
{
// First of all, we need to figure out what size we need.
u32 actual_size = 16;
if (fmt.object_id)
actual_size += sizeof(CmifDomainInHeader) + fmt.num_objects*sizeof(u32);
actual_size += sizeof(CmifInHeader) + fmt.data_size;
actual_size = (actual_size + 1) &~ 1; // hword-align
u32 out_pointer_size_table_offset = actual_size;
u32 out_pointer_size_table_size = fmt.num_out_auto_buffers + fmt.num_out_pointers;
actual_size += sizeof(u16)*out_pointer_size_table_size;
u32 num_data_words = (actual_size + 3) / 4;
CmifRequest req = {};
req.hipc = hipcMakeRequestInline(base,
.type = fmt.context ? CmifCommandType_RequestWithContext : CmifCommandType_Request,
.num_send_statics = fmt.num_in_auto_buffers + fmt.num_in_pointers,
.num_send_buffers = fmt.num_in_auto_buffers + fmt.num_in_buffers,
.num_recv_buffers = fmt.num_out_auto_buffers + fmt.num_out_buffers,
.num_exch_buffers = fmt.num_inout_buffers,
.num_data_words = num_data_words,
.num_recv_statics = out_pointer_size_table_size + fmt.num_out_fixed_pointers,
.send_pid = fmt.send_pid,
.num_copy_handles = fmt.num_handles,
.num_move_handles = 0,
);
CmifInHeader* hdr = NULL;
void* start = cmifGetAlignedDataStart(req.hipc.data_words, base);
if (fmt.object_id) {
CmifDomainInHeader* domain_hdr = (CmifDomainInHeader*)start;
u32 payload_size = sizeof(CmifInHeader) + fmt.data_size;
*domain_hdr = (CmifDomainInHeader){
.type = CmifDomainRequestType_SendMessage,
.num_in_objects = (u8)fmt.num_objects,
.data_size = (u16)payload_size,
.object_id = fmt.object_id,
.padding = 0,
.token = fmt.context,
};
hdr = (CmifInHeader*)(domain_hdr+1);
req.objects = (u32*)((u8*)hdr + payload_size);
} else
hdr = (CmifInHeader*)start;
*hdr = (CmifInHeader){
.magic = CMIF_IN_HEADER_MAGIC,
.version = fmt.context ? 1U : 0U,
.command_id = fmt.request_id,
.token = fmt.object_id ? 0U : fmt.context,
};
req.data = hdr+1;
req.out_pointer_sizes = (u16*)(void*)((u8*)(void*)req.hipc.data_words + out_pointer_size_table_offset);
req.server_pointer_size = fmt.server_pointer_size;
return req;
}
NX_CONSTEXPR void* cmifMakeControlRequest(void* base, u32 request_id, u32 size)
{
u32 actual_size = 16 + sizeof(CmifInHeader) + size;
HipcRequest hipc = hipcMakeRequestInline(base,
.type = CmifCommandType_Control,
.num_data_words = (actual_size + 3) / 4,
);
CmifInHeader* hdr = (CmifInHeader*)cmifGetAlignedDataStart(hipc.data_words, base);
*hdr = (CmifInHeader){
.magic = CMIF_IN_HEADER_MAGIC,
.version = 0,
.command_id = request_id,
.token = 0,
};
return hdr+1;
}
NX_CONSTEXPR void cmifMakeCloseRequest(void* base, u32 object_id)
{
if (object_id) {
HipcRequest hipc = hipcMakeRequestInline(base,
.type = CmifCommandType_Request,
.num_data_words = (16 + sizeof(CmifDomainInHeader)) / 4,
);
CmifDomainInHeader* domain_hdr = (CmifDomainInHeader*)cmifGetAlignedDataStart(hipc.data_words, base);
*domain_hdr = (CmifDomainInHeader){
.type = CmifDomainRequestType_Close,
.object_id = object_id,
};
} else {
hipcMakeRequestInline(base,
.type = CmifCommandType_Close,
);
}
}
NX_CONSTEXPR void cmifRequestInBuffer(CmifRequest* req, const void* buffer, size_t size, HipcBufferMode mode)
{
*req->hipc.send_buffers++ = hipcMakeBuffer(buffer, size, mode);
}
NX_CONSTEXPR void cmifRequestOutBuffer(CmifRequest* req, void* buffer, size_t size, HipcBufferMode mode)
{
*req->hipc.recv_buffers++ = hipcMakeBuffer(buffer, size, mode);
}
NX_CONSTEXPR void cmifRequestInOutBuffer(CmifRequest* req, void* buffer, size_t size, HipcBufferMode mode)
{
*req->hipc.exch_buffers++ = hipcMakeBuffer(buffer, size, mode);
}
NX_CONSTEXPR void cmifRequestInPointer(CmifRequest* req, const void* buffer, size_t size)
{
*req->hipc.send_statics++ = hipcMakeSendStatic(buffer, size, req->cur_in_ptr_id++);
req->server_pointer_size -= size;
}
NX_CONSTEXPR void cmifRequestOutFixedPointer(CmifRequest* req, void* buffer, size_t size)
{
*req->hipc.recv_list++ = hipcMakeRecvStatic(buffer, size);
req->server_pointer_size -= size;
}
NX_CONSTEXPR void cmifRequestOutPointer(CmifRequest* req, void* buffer, size_t size)
{
cmifRequestOutFixedPointer(req, buffer, size);
*req->out_pointer_sizes++ = size;
}
NX_CONSTEXPR void cmifRequestInAutoBuffer(CmifRequest* req, const void* buffer, size_t size)
{
if (req->server_pointer_size && size <= req->server_pointer_size) {
cmifRequestInPointer(req, buffer, size);
cmifRequestInBuffer(req, NULL, 0, HipcBufferMode_Normal);
} else {
cmifRequestInPointer(req, NULL, 0);
cmifRequestInBuffer(req, buffer, size, HipcBufferMode_Normal);
}
}
NX_CONSTEXPR void cmifRequestOutAutoBuffer(CmifRequest* req, void* buffer, size_t size)
{
if (req->server_pointer_size && size <= req->server_pointer_size) {
cmifRequestOutPointer(req, buffer, size);
cmifRequestOutBuffer(req, NULL, 0, HipcBufferMode_Normal);
} else {
cmifRequestOutPointer(req, NULL, 0);
cmifRequestOutBuffer(req, buffer, size, HipcBufferMode_Normal);
}
}
NX_CONSTEXPR void cmifRequestObject(CmifRequest* req, u32 object_id)
{
*req->objects++ = object_id;
}
NX_CONSTEXPR void cmifRequestHandle(CmifRequest* req, Handle handle)
{
*req->hipc.copy_handles++ = handle;
}
NX_CONSTEXPR Result cmifParseResponse(CmifResponse* res, void* base, bool is_domain, u32 size)
{
HipcResponse hipc = hipcParseResponse(base);
void* start = cmifGetAlignedDataStart(hipc.data_words, base);
CmifOutHeader* hdr = NULL;
u32* objects = NULL;
if (is_domain) {
CmifDomainOutHeader* domain_hdr = (CmifDomainOutHeader*)start;
hdr = (CmifOutHeader*)(domain_hdr+1);
objects = (u32*)((u8*)hdr + sizeof(CmifOutHeader) + size);
}
else
hdr = (CmifOutHeader*)start;
if (hdr->magic != CMIF_OUT_HEADER_MAGIC)
return MAKERESULT(Module_Libnx, LibnxError_InvalidCmifOutHeader);
if (R_FAILED(hdr->result))
return hdr->result;
*res = (CmifResponse){
.data = hdr+1,
.objects = objects,
.copy_handles = hipc.copy_handles,
.move_handles = hipc.move_handles,
};
return 0;
}
NX_CONSTEXPR u32 cmifResponseGetObject(CmifResponse* res)
{
return *res->objects++;
}
NX_CONSTEXPR Handle cmifResponseGetCopyHandle(CmifResponse* res)
{
return *res->copy_handles++;
}
NX_CONSTEXPR Handle cmifResponseGetMoveHandle(CmifResponse* res)
{
return *res->move_handles++;
}
NX_INLINE Result cmifConvertCurrentObjectToDomain(Handle h, u32* out_object_id)
{
cmifMakeControlRequest(armGetTls(), 0, 0);
Result rc = svcSendSyncRequest(h);
if (R_SUCCEEDED(rc)) {
CmifResponse resp = {};
rc = cmifParseResponse(&resp, armGetTls(), false, sizeof(u32));
if (R_SUCCEEDED(rc) && out_object_id)
*out_object_id = *(u32*)resp.data;
}
return rc;
}
NX_INLINE Result cmifCopyFromCurrentDomain(Handle h, u32 object_id, Handle* out_h)
{
void* raw = cmifMakeControlRequest(armGetTls(), 1, sizeof(u32));
*(u32*)raw = object_id;
Result rc = svcSendSyncRequest(h);
if (R_SUCCEEDED(rc)) {
CmifResponse resp = {};
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
if (R_SUCCEEDED(rc) && out_h)
*out_h = resp.move_handles[0];
}
return rc;
}
NX_INLINE Result cmifCloneCurrentObject(Handle h, Handle* out_h)
{
cmifMakeControlRequest(armGetTls(), 2, 0);
Result rc = svcSendSyncRequest(h);
if (R_SUCCEEDED(rc)) {
CmifResponse resp = {};
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
if (R_SUCCEEDED(rc) && out_h)
*out_h = resp.move_handles[0];
}
return rc;
}
NX_INLINE Result cmifQueryPointerBufferSize(Handle h, u16* out_size)
{
cmifMakeControlRequest(armGetTls(), 3, 0);
Result rc = svcSendSyncRequest(h);
if (R_SUCCEEDED(rc)) {
CmifResponse resp = {};
rc = cmifParseResponse(&resp, armGetTls(), false, sizeof(u16));
if (R_SUCCEEDED(rc) && out_size)
*out_size = *(u16*)resp.data;
}
return rc;
}
NX_INLINE Result cmifCloneCurrentObjectEx(Handle h, u32 tag, Handle* out_h)
{
void* raw = cmifMakeControlRequest(armGetTls(), 4, sizeof(u32));
*(u32*)raw = tag;
Result rc = svcSendSyncRequest(h);
if (R_SUCCEEDED(rc)) {
CmifResponse resp = {};
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
if (R_SUCCEEDED(rc) && out_h)
*out_h = resp.move_handles[0];
}
return rc;
}

363
nx/include/switch/sf/hipc.h Normal file
View File

@ -0,0 +1,363 @@
/**
* @file hipc.h
* @brief Horizon Inter-Process Communication protocol
* @author fincs
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include "../result.h"
#include "../arm/tls.h"
#include "../kernel/svc.h"
#define HIPC_AUTO_RECV_STATIC UINT8_MAX
#define HIPC_RESPONSE_NO_PID UINT32_MAX
typedef struct HipcMetadata {
u32 type;
u32 num_send_statics;
u32 num_send_buffers;
u32 num_recv_buffers;
u32 num_exch_buffers;
u32 num_data_words;
u32 num_recv_statics; // also accepts HIPC_AUTO_RECV_STATIC
u32 send_pid;
u32 num_copy_handles;
u32 num_move_handles;
} HipcMetadata;
typedef struct HipcHeader {
u32 type : 16;
u32 num_send_statics : 4;
u32 num_send_buffers : 4;
u32 num_recv_buffers : 4;
u32 num_exch_buffers : 4;
u32 num_data_words : 10;
u32 recv_static_mode : 4;
u32 padding : 6;
u32 recv_list_offset : 11; // Unused.
u32 has_special_header : 1;
} HipcHeader;
typedef struct HipcSpecialHeader {
u32 send_pid : 1;
u32 num_copy_handles : 4;
u32 num_move_handles : 4;
u32 padding : 23;
} HipcSpecialHeader;
typedef struct HipcStaticDescriptor {
u32 index : 6;
u32 address_high : 6;
u32 address_mid : 4;
u32 size : 16;
u32 address_low;
} HipcStaticDescriptor;
typedef struct HipcBufferDescriptor {
u32 size_low;
u32 address_low;
u32 mode : 2;
u32 address_high : 22;
u32 size_high : 4;
u32 address_mid : 4;
} HipcBufferDescriptor;
typedef struct HipcRecvListEntry {
u32 address_low;
u32 address_high : 16;
u32 size : 16;
} HipcRecvListEntry;
typedef struct HipcRequest {
HipcStaticDescriptor* send_statics;
HipcBufferDescriptor* send_buffers;
HipcBufferDescriptor* recv_buffers;
HipcBufferDescriptor* exch_buffers;
u32* data_words;
HipcRecvListEntry* recv_list;
Handle* copy_handles;
Handle* move_handles;
} HipcRequest;
typedef struct HipcParsedRequest {
HipcMetadata meta;
HipcRequest data;
u64 pid;
} HipcParsedRequest;
typedef struct HipcResponse {
u64 pid;
u32 num_statics;
u32 num_data_words;
u32 num_copy_handles;
u32 num_move_handles;
HipcStaticDescriptor* statics;
u32* data_words;
Handle* copy_handles;
Handle* move_handles;
} HipcResponse;
typedef enum HipcBufferMode {
HipcBufferMode_Normal = 0,
HipcBufferMode_NonSecure = 1,
HipcBufferMode_Invalid = 2,
HipcBufferMode_NonDevice = 3,
} HipcBufferMode;
NX_CONSTEXPR HipcStaticDescriptor hipcMakeSendStatic(const void* buffer, size_t size, u8 index)
{
return (HipcStaticDescriptor){
.index = index,
.address_high = (u32)((uintptr_t)buffer >> 36),
.address_mid = (u32)((uintptr_t)buffer >> 32),
.size = (u32)size,
.address_low = (u32)(uintptr_t)buffer,
};
}
NX_CONSTEXPR HipcBufferDescriptor hipcMakeBuffer(const void* buffer, size_t size, HipcBufferMode mode)
{
return (HipcBufferDescriptor){
.size_low = (u32)size,
.address_low = (u32)(uintptr_t)buffer,
.mode = mode,
.address_high = (u32)((uintptr_t)buffer >> 36),
.size_high = (u32)(size >> 32),
.address_mid = (u32)((uintptr_t)buffer >> 32),
};
}
NX_CONSTEXPR HipcRecvListEntry hipcMakeRecvStatic(void* buffer, size_t size)
{
return (HipcRecvListEntry){
.address_low = (u32)((uintptr_t)buffer),
.address_high = (u32)((uintptr_t)buffer >> 32),
.size = (u32)size,
};
}
NX_CONSTEXPR void* hipcGetStaticAddress(const HipcStaticDescriptor* desc)
{
return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
}
NX_CONSTEXPR size_t hipcGetStaticSize(const HipcStaticDescriptor* desc)
{
return desc->size;
}
NX_CONSTEXPR void* hipcGetBufferAddress(const HipcBufferDescriptor* desc)
{
return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
}
NX_CONSTEXPR size_t hipcGetBufferSize(const HipcBufferDescriptor* desc)
{
return desc->size_low | ((size_t)desc->size_high << 32);
}
NX_CONSTEXPR HipcRequest hipcCalcRequestLayout(HipcMetadata meta, void* base)
{
// Copy handles
Handle* copy_handles = NULL;
if (meta.num_copy_handles) {
copy_handles = (Handle*)base;
base = copy_handles + meta.num_copy_handles;
}
// Move handles
Handle* move_handles = NULL;
if (meta.num_move_handles) {
move_handles = (Handle*)base;
base = move_handles + meta.num_move_handles;
}
// Send statics
HipcStaticDescriptor* send_statics = NULL;
if (meta.num_send_statics) {
send_statics = (HipcStaticDescriptor*)base;
base = send_statics + meta.num_send_statics;
}
// Send buffers
HipcBufferDescriptor* send_buffers = NULL;
if (meta.num_send_buffers) {
send_buffers = (HipcBufferDescriptor*)base;
base = send_buffers + meta.num_send_buffers;
}
// Recv buffers
HipcBufferDescriptor* recv_buffers = NULL;
if (meta.num_recv_buffers) {
recv_buffers = (HipcBufferDescriptor*)base;
base = recv_buffers + meta.num_recv_buffers;
}
// Exch buffers
HipcBufferDescriptor* exch_buffers = NULL;
if (meta.num_exch_buffers) {
exch_buffers = (HipcBufferDescriptor*)base;
base = exch_buffers + meta.num_exch_buffers;
}
// Data words
u32* data_words = NULL;
if (meta.num_data_words) {
data_words = (u32*)base;
base = data_words + meta.num_data_words;
}
// Recv list
HipcRecvListEntry* recv_list = NULL;
if (meta.num_recv_statics)
recv_list = (HipcRecvListEntry*)base;
return (HipcRequest){
.send_statics = send_statics,
.send_buffers = send_buffers,
.recv_buffers = recv_buffers,
.exch_buffers = exch_buffers,
.data_words = data_words,
.recv_list = recv_list,
.copy_handles = copy_handles,
.move_handles = move_handles,
};
}
NX_CONSTEXPR HipcRequest hipcMakeRequest(void* base, HipcMetadata meta)
{
// Write message header
bool has_special_header = meta.send_pid || meta.num_copy_handles || meta.num_move_handles;
HipcHeader* hdr = (HipcHeader*)base;
base = hdr+1;
*hdr = (HipcHeader){
.type = meta.type,
.num_send_statics = meta.num_send_statics,
.num_send_buffers = meta.num_send_buffers,
.num_recv_buffers = meta.num_recv_buffers,
.num_exch_buffers = meta.num_exch_buffers,
.num_data_words = meta.num_data_words,
.recv_static_mode = meta.num_recv_statics ? (meta.num_recv_statics != HIPC_AUTO_RECV_STATIC ? 2u + meta.num_recv_statics : 2u) : 0u,
.padding = 0,
.recv_list_offset = 0,
.has_special_header = has_special_header,
};
// Write special header
if (has_special_header) {
HipcSpecialHeader* sphdr = (HipcSpecialHeader*)base;
base = sphdr+1;
*sphdr = (HipcSpecialHeader){
.send_pid = meta.send_pid,
.num_copy_handles = meta.num_copy_handles,
.num_move_handles = meta.num_move_handles,
};
if (meta.send_pid)
base = (u8*)base + sizeof(u64);
}
// Calculate layout
return hipcCalcRequestLayout(meta, base);
}
#define hipcMakeRequestInline(_base,...) hipcMakeRequest((_base),(HipcMetadata){ __VA_ARGS__ })
NX_CONSTEXPR HipcParsedRequest hipcParseRequest(void* base)
{
// Parse message header
HipcHeader hdr = {};
__builtin_memcpy(&hdr, base, sizeof(hdr));
base = (u8*)base + sizeof(hdr);
u32 num_recv_statics = 0;
u64 pid = 0;
// Parse recv static mode
if (hdr.recv_static_mode) {
if (hdr.recv_static_mode == 2u)
num_recv_statics = HIPC_AUTO_RECV_STATIC;
else if (hdr.recv_static_mode > 2u)
num_recv_statics = hdr.recv_static_mode - 2u;
}
// Parse special header
HipcSpecialHeader sphdr = {};
if (hdr.has_special_header) {
__builtin_memcpy(&sphdr, base, sizeof(sphdr));
base = (u8*)base + sizeof(sphdr);
// Read PID descriptor
if (sphdr.send_pid) {
pid = *(u64*)base;
base = (u8*)base + sizeof(u64);
}
}
const HipcMetadata meta = {
.type = hdr.type,
.num_send_statics = hdr.num_send_statics,
.num_send_buffers = hdr.num_send_buffers,
.num_recv_buffers = hdr.num_recv_buffers,
.num_exch_buffers = hdr.num_exch_buffers,
.num_data_words = hdr.num_data_words,
.num_recv_statics = num_recv_statics,
.send_pid = sphdr.send_pid,
.num_copy_handles = sphdr.num_copy_handles,
.num_move_handles = sphdr.num_move_handles,
};
return (HipcParsedRequest){
.meta = meta,
.data = hipcCalcRequestLayout(meta, base),
.pid = pid,
};
}
NX_CONSTEXPR HipcResponse hipcParseResponse(void* base)
{
// Parse header
HipcHeader hdr = {};
__builtin_memcpy(&hdr, base, sizeof(hdr));
base = (u8*)base + sizeof(hdr);
// Initialize response
HipcResponse response = {};
response.num_statics = hdr.num_send_statics;
response.num_data_words = hdr.num_data_words;
response.pid = HIPC_RESPONSE_NO_PID;
// Parse special header
if (hdr.has_special_header)
{
HipcSpecialHeader sphdr = {};
__builtin_memcpy(&sphdr, base, sizeof(sphdr));
base = (u8*)base + sizeof(sphdr);
// Update response
response.num_copy_handles = sphdr.num_copy_handles;
response.num_move_handles = sphdr.num_move_handles;
// Parse PID descriptor
if (sphdr.send_pid) {
response.pid = *(u64*)base;
base = (u8*)base + sizeof(u64);
}
}
// Copy handles
response.copy_handles = (Handle*)base;
base = response.copy_handles + response.num_copy_handles;
// Move handles
response.move_handles = (Handle*)base;
base = response.move_handles + response.num_move_handles;
// Send statics
response.statics = (HipcStaticDescriptor*)base;
base = response.statics + response.num_statics;
// Data words
response.data_words = (u32*)base;
return response;
}

View File

@ -0,0 +1,459 @@
/**
* @file service.h
* @brief Service wrapper object
* @author fincs
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include "hipc.h"
#include "cmif.h"
/// Service object structure
typedef struct Service {
Handle session;
u32 own_handle;
u32 object_id;
u16 pointer_buffer_size;
} Service;
enum {
SfBufferAttr_In = BIT(0),
SfBufferAttr_Out = BIT(1),
SfBufferAttr_HipcMapAlias = BIT(2),
SfBufferAttr_HipcPointer = BIT(3),
SfBufferAttr_FixedSize = BIT(4),
SfBufferAttr_HipcAutoSelect = BIT(5),
SfBufferAttr_HipcMapTransferAllowsNonSecure = BIT(6),
SfBufferAttr_HipcMapTransferAllowsNonDevice = BIT(7),
};
typedef struct SfBufferAttrs {
u32 attr0;
u32 attr1;
u32 attr2;
u32 attr3;
u32 attr4;
u32 attr5;
u32 attr6;
u32 attr7;
} SfBufferAttrs;
typedef struct SfBuffer {
const void* ptr;
size_t size;
} SfBuffer;
typedef enum SfOutHandleAttr {
SfOutHandleAttr_None = 0,
SfOutHandleAttr_HipcCopy = 1,
SfOutHandleAttr_HipcMove = 2,
} SfOutHandleAttr;
typedef struct SfOutHandleAttrs {
SfOutHandleAttr attr0;
SfOutHandleAttr attr1;
SfOutHandleAttr attr2;
SfOutHandleAttr attr3;
SfOutHandleAttr attr4;
SfOutHandleAttr attr5;
SfOutHandleAttr attr6;
SfOutHandleAttr attr7;
} SfOutHandleAttrs;
typedef struct SfDispatchParams {
Handle target_session;
u32 context;
SfBufferAttrs buffer_attrs;
SfBuffer buffers[8];
bool in_send_pid;
u32 in_num_objects;
const Service* in_objects[8];
u32 in_num_handles;
Handle in_handles[8];
u32 out_num_objects;
Service* out_objects;
SfOutHandleAttrs out_handle_attrs;
Handle* out_handles;
} SfDispatchParams;
/**
* @brief Returns whether a service has been initialized.
* @param[in] s Service object.
* @return true if initialized.
*/
NX_CONSTEXPR bool serviceIsActive(Service* s) {
return s->session != INVALID_HANDLE;
}
/**
* @brief Returns whether a service is overriden in the homebrew environment.
* @param[in] s Service object.
* @return true if overriden.
*/
NX_CONSTEXPR bool serviceIsOverride(Service* s) {
return serviceIsActive(s) && !s->own_handle && !s->object_id;
}
/**
* @brief Returns whether a service is a domain.
* @param[in] s Service object.
* @return true if a domain.
*/
NX_CONSTEXPR bool serviceIsDomain(Service* s) {
return serviceIsActive(s) && s->own_handle && s->object_id;
}
/**
* @brief Returns whether a service is a domain subservice.
* @param[in] s Service object.
* @return true if a domain subservice.
*/
NX_CONSTEXPR bool serviceIsDomainSubservice(Service* s) {
return serviceIsActive(s) && !s->own_handle && s->object_id;
}
/**
* @brief For a domain/domain subservice, return the associated object ID.
* @param[in] s Service object, necessarily a domain or domain subservice.
* @return The object ID.
*/
NX_CONSTEXPR u32 serviceGetObjectId(Service* s) {
return s->object_id;
}
/**
* @brief Creates a service object from an IPC session handle.
* @param[out] s Service object.
* @param[in] h IPC session handle.
*/
NX_INLINE void serviceCreate(Service* s, Handle h)
{
s->session = h;
s->own_handle = 1;
s->object_id = 0;
s->pointer_buffer_size = 0;
cmifQueryPointerBufferSize(h, &s->pointer_buffer_size);
}
/**
* @brief Creates a domain subservice object from a parent service.
* @param[out] s Service object.
* @param[in] parent Parent service, necessarily a domain or domain subservice.
* @param[in] object_id Object ID for this subservice.
*/
NX_CONSTEXPR void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id)
{
s->session = parent->session;
s->own_handle = 0;
s->object_id = object_id;
s->pointer_buffer_size = parent->pointer_buffer_size;
}
/**
* @brief Hints the compiler that a service will always contain a domain object.
* @param[in] _s Service object.
*/
#define serviceAssumeDomain(_s) do { \
if (!(_s)->object_id) \
__builtin_unreachable(); \
} while(0)
/**
* @brief Closes a service.
* @param[in] s Service object.
*/
NX_INLINE void serviceClose(Service* s)
{
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
if (s->object_id)
__builtin_unreachable();
#endif
if (s->own_handle || s->object_id) {
cmifMakeCloseRequest(armGetTls(), s->own_handle ? 0 : s->object_id);
svcSendSyncRequest(s->session);
if (s->own_handle)
svcCloseHandle(s->session);
}
*s = (Service){};
}
/**
* @brief Clones a service.
* @param[in] s Service object.
* @param[out] out_s Output service object.
*/
NX_INLINE Result serviceClone(Service* s, Service* out_s)
{
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
if (s->object_id)
__builtin_unreachable();
#endif
out_s->session = 0;
out_s->own_handle = 1;
out_s->object_id = s->object_id;
out_s->pointer_buffer_size = s->pointer_buffer_size;
return cmifCloneCurrentObject(s->session, &out_s->session);
}
/**
* @brief Clones a service with a session manager tag.
* @param[in] s Service object.
* @param[in] tag Session manager tag (unused in current official server code)
* @param[out] out_s Output service object.
*/
NX_INLINE Result serviceCloneEx(Service* s, u32 tag, Service* out_s)
{
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
if (s->object_id)
__builtin_unreachable();
#endif
out_s->session = 0;
out_s->own_handle = 1;
out_s->object_id = s->object_id;
out_s->pointer_buffer_size = s->pointer_buffer_size;
return cmifCloneCurrentObjectEx(s->session, tag, &out_s->session);
}
/**
* @brief Converts a regular service to a domain.
* @param[in] s Service object.
* @return Result code.
*/
NX_INLINE Result serviceConvertToDomain(Service* s)
{
if (!s->own_handle) {
// For overridden services, create a clone first.
Result rc = cmifCloneCurrentObjectEx(s->session, 0, &s->session);
if (R_FAILED(rc))
return rc;
s->own_handle = 1;
}
return cmifConvertCurrentObjectToDomain(s->session, &s->object_id);
}
NX_CONSTEXPR void _serviceRequestFormatProcessBuffer(CmifRequestFormat* fmt, u32 attr)
{
if (!attr) return;
const bool is_in = (attr & SfBufferAttr_In) != 0;
const bool is_out = (attr & SfBufferAttr_Out) != 0;
if (attr & SfBufferAttr_HipcAutoSelect) {
if (is_in)
fmt->num_in_auto_buffers ++;
if (is_out)
fmt->num_out_auto_buffers ++;
} else if (attr & SfBufferAttr_HipcPointer) {
if (is_in)
fmt->num_in_pointers ++;
if (is_out) {
if (attr & SfBufferAttr_FixedSize)
fmt->num_out_fixed_pointers ++;
else
fmt->num_out_pointers ++;
}
} else if (attr & SfBufferAttr_HipcMapAlias) {
if (is_in && is_out)
fmt->num_inout_buffers ++;
else if (is_in)
fmt->num_in_buffers ++;
else if (is_out)
fmt->num_out_buffers ++;
}
}
NX_CONSTEXPR void _serviceRequestProcessBuffer(CmifRequest* req, const SfBuffer* buf, u32 attr)
{
if (!attr) return;
const bool is_in = (attr & SfBufferAttr_In);
const bool is_out = (attr & SfBufferAttr_Out);
if (attr & SfBufferAttr_HipcAutoSelect) {
if (is_in)
cmifRequestInAutoBuffer(req, buf->ptr, buf->size);
if (is_out)
cmifRequestOutAutoBuffer(req, (void*)buf->ptr, buf->size);
} else if (attr & SfBufferAttr_HipcPointer) {
if (is_in)
cmifRequestInPointer(req, buf->ptr, buf->size);
if (is_out) {
if (attr & SfBufferAttr_FixedSize)
cmifRequestOutFixedPointer(req, (void*)buf->ptr, buf->size);
else
cmifRequestOutPointer(req, (void*)buf->ptr, buf->size);
}
} else if (attr & SfBufferAttr_HipcMapAlias) {
HipcBufferMode mode = HipcBufferMode_Normal;
if (attr & SfBufferAttr_HipcMapTransferAllowsNonSecure)
mode = HipcBufferMode_NonSecure;
if (attr & SfBufferAttr_HipcMapTransferAllowsNonDevice)
mode = HipcBufferMode_NonDevice;
if (is_in && is_out)
cmifRequestInOutBuffer(req, (void*)buf->ptr, buf->size, mode);
else if (is_in)
cmifRequestInBuffer(req, buf->ptr, buf->size, mode);
else if (is_out)
cmifRequestOutBuffer(req, (void*)buf->ptr, buf->size, mode);
}
}
NX_INLINE void* serviceMakeRequest(
Service* s, u32 request_id, u32 context, u32 data_size, bool send_pid,
const SfBufferAttrs buffer_attrs, const SfBuffer* buffers,
u32 num_objects, const Service* const* objects,
u32 num_handles, const Handle* handles
) {
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
if (s->object_id)
__builtin_unreachable();
#endif
CmifRequestFormat fmt = {};
fmt.object_id = s->object_id;
fmt.request_id = request_id;
fmt.context = context;
fmt.data_size = data_size;
fmt.server_pointer_size = s->pointer_buffer_size;
fmt.num_objects = num_objects;
fmt.num_handles = num_handles;
fmt.send_pid = send_pid;
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr0);
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr1);
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr2);
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr3);
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr4);
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr5);
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr6);
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr7);
CmifRequest req = cmifMakeRequest(armGetTls(), fmt);
if (s->object_id) // TODO: Check behavior of input objects in non-domain sessions
for (u32 i = 0; i < num_objects; i ++)
cmifRequestObject(&req, objects[i]->object_id);
for (u32 i = 0; i < num_handles; i ++)
cmifRequestHandle(&req, handles[i]);
_serviceRequestProcessBuffer(&req, &buffers[0], buffer_attrs.attr0);
_serviceRequestProcessBuffer(&req, &buffers[1], buffer_attrs.attr1);
_serviceRequestProcessBuffer(&req, &buffers[2], buffer_attrs.attr2);
_serviceRequestProcessBuffer(&req, &buffers[3], buffer_attrs.attr3);
_serviceRequestProcessBuffer(&req, &buffers[4], buffer_attrs.attr4);
_serviceRequestProcessBuffer(&req, &buffers[5], buffer_attrs.attr5);
_serviceRequestProcessBuffer(&req, &buffers[6], buffer_attrs.attr6);
_serviceRequestProcessBuffer(&req, &buffers[7], buffer_attrs.attr7);
return req.data;
}
NX_CONSTEXPR void _serviceResponseGetHandle(CmifResponse* res, SfOutHandleAttr type, Handle* out)
{
switch (type) {
default:
case SfOutHandleAttr_None:
break;
case SfOutHandleAttr_HipcCopy:
*out = cmifResponseGetCopyHandle(res);
break;
case SfOutHandleAttr_HipcMove:
*out = cmifResponseGetMoveHandle(res);
break;
}
}
NX_INLINE Result serviceParseResponse(
Service* s, u32 out_size, void** out_data,
u32 num_out_objects, Service* out_objects,
const SfOutHandleAttrs out_handle_attrs, Handle* out_handles
) {
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
if (s->object_id)
__builtin_unreachable();
#endif
CmifResponse res = {};
bool is_domain = s->object_id != 0;
Result rc = cmifParseResponse(&res, armGetTls(), is_domain, out_size);
if (R_FAILED(rc))
return rc;
if (out_size)
*out_data = res.data;
for (u32 i = 0; i < num_out_objects; i ++) {
if (is_domain)
serviceCreateDomainSubservice(&out_objects[i], s, cmifResponseGetObject(&res));
else // Output objects are marshalled as move handles at the beginning of the list.
serviceCreate(&out_objects[i], cmifResponseGetMoveHandle(&res));
}
_serviceResponseGetHandle(&res, out_handle_attrs.attr0, &out_handles[0]);
_serviceResponseGetHandle(&res, out_handle_attrs.attr1, &out_handles[1]);
_serviceResponseGetHandle(&res, out_handle_attrs.attr2, &out_handles[2]);
_serviceResponseGetHandle(&res, out_handle_attrs.attr3, &out_handles[3]);
_serviceResponseGetHandle(&res, out_handle_attrs.attr4, &out_handles[4]);
_serviceResponseGetHandle(&res, out_handle_attrs.attr5, &out_handles[5]);
_serviceResponseGetHandle(&res, out_handle_attrs.attr6, &out_handles[6]);
_serviceResponseGetHandle(&res, out_handle_attrs.attr7, &out_handles[7]);
return 0;
}
NX_INLINE Result serviceDispatchImpl(
Service* s, u32 request_id,
const void* in_data, u32 in_data_size,
void* out_data, u32 out_data_size,
SfDispatchParams disp
)
{
// Make a copy of the service struct, so that the compiler can assume that it won't be modified by function calls.
Service srv = *s;
void* in = serviceMakeRequest(&srv, request_id, disp.context,
in_data_size, disp.in_send_pid,
disp.buffer_attrs, disp.buffers,
disp.in_num_objects, disp.in_objects,
disp.in_num_handles, disp.in_handles);
if (in_data_size)
__builtin_memcpy(in, in_data, in_data_size);
Result rc = svcSendSyncRequest(disp.target_session == INVALID_HANDLE ? s->session : disp.target_session);
if (R_SUCCEEDED(rc)) {
void* out = NULL;
rc = serviceParseResponse(&srv,
out_data_size, &out,
disp.out_num_objects, disp.out_objects,
disp.out_handle_attrs, disp.out_handles);
if (R_SUCCEEDED(rc) && out_data && out_data_size)
__builtin_memcpy(out_data, out, out_data_size);
}
return rc;
}
#define serviceDispatch(_s,_rid,...) \
serviceDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ })
#define serviceDispatchIn(_s,_rid,_in,...) \
serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ })
#define serviceDispatchOut(_s,_rid,_out,...) \
serviceDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })
#define serviceDispatchInOut(_s,_rid,_in,_out,...) \
serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })

View File

@ -77,5 +77,15 @@ typedef void (*VoidFn)(void); ///< Function without arguments nor return v
#endif #endif
#endif #endif
/// Flags a function as (always) inline.
#define NX_INLINE __attribute__((always_inline)) static inline
/// Flags a function as constexpr in C++14 and above; or as (always) inline otherwise.
#if __cplusplus >= 201402L
#define NX_CONSTEXPR NX_INLINE constexpr
#else
#define NX_CONSTEXPR NX_INLINE
#endif
/// Invalid handle. /// Invalid handle.
#define INVALID_HANDLE ((Handle) 0) #define INVALID_HANDLE ((Handle) 0)

View File

@ -0,0 +1,31 @@
#include <string.h>
#include "types.h"
#include "result.h"
#include "services/applet.h"
#include "applets/libapplet.h"
#include "applets/album_la.h"
static Result _albumLaShow(u8 arg, bool playStartupSound) {
Result rc=0;
LibAppletArgs commonargs;
libappletArgsCreate(&commonargs, 0x10000);
libappletArgsSetPlayStartupSound(&commonargs, playStartupSound);
rc = libappletLaunch(AppletId_photoViewer, &commonargs, &arg, sizeof(arg), NULL, 0, NULL);
return rc;
}
Result albumLaShowAlbumFiles(void) {
return _albumLaShow(AlbumLaArg_ShowAlbumFiles, false);
}
Result albumLaShowAllAlbumFiles(void) {
return _albumLaShow(AlbumLaArg_ShowAllAlbumFiles, false);
}
Result albumLaShowAllAlbumFilesForHomeMenu(void) {
return _albumLaShow(AlbumLaArg_ShowAllAlbumFilesForHomeMenu, true);
}

View File

@ -214,7 +214,9 @@ Result errorSystemCreate(ErrorSystemConfig* c, const char* dialog_message, const
if (hosversionBefore(5,0,0)) { if (hosversionBefore(5,0,0)) {
rc = setInitialize(); rc = setInitialize();
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &c->arg.languageCode); u64 languageCode = 0;
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &languageCode);
if (R_SUCCEEDED(rc)) c->arg.languageCode = languageCode;
setExit(); setExit();
} }
@ -247,7 +249,9 @@ Result errorApplicationCreate(ErrorApplicationConfig* c, const char* dialog_mess
if (hosversionBefore(5,0,0)) { if (hosversionBefore(5,0,0)) {
rc = setInitialize(); rc = setInitialize();
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &c->arg.languageCode); u64 languageCode = 0;
if (R_SUCCEEDED(rc)) rc = setMakeLanguageCode(SetLanguage_ENUS, &languageCode);
if (R_SUCCEEDED(rc)) c->arg.languageCode = languageCode;
setExit(); setExit();
} }

View File

@ -0,0 +1,76 @@
#include <string.h>
#include "types.h"
#include "result.h"
#include "services/acc.h"
#include "services/applet.h"
#include "applets/libapplet.h"
#include "applets/friends_la.h"
static Result _friendsLaShow(const FriendsLaArg *arg, bool playStartupSound) {
Result rc=0;
Result rc2=0;
size_t readsize=0;
LibAppletArgs commonargs;
libappletArgsCreate(&commonargs, 0x1);
libappletArgsSetPlayStartupSound(&commonargs, playStartupSound);
if (arg->type != FriendsLaArgType_StartSendingFriendRequest)
rc = libappletLaunch(AppletId_myPage, &commonargs, arg, sizeof(*arg), NULL, 0, NULL);
else {
rc = libappletLaunch(AppletId_myPage, &commonargs, arg, sizeof(*arg), &rc2, sizeof(rc2), &readsize);
if (R_SUCCEEDED(rc) && readsize!=sizeof(rc2)) rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (R_SUCCEEDED(rc)) rc = rc2;
}
return rc;
}
static Result _friendsLaShowSimple(FriendsLaArgType type, AccountUid *userID, bool playStartupSound) {
FriendsLaArg arg = {.type = type, .userID = *userID};
return _friendsLaShow(&arg, playStartupSound);
}
static Result _friendsLaShowAll(FriendsLaArgType type, AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName, bool playStartupSound) {
FriendsLaArg arg = {.type = type, .userID = *userID, .networkServiceAccountId = networkServiceAccountId, .first_inAppScreenName = *first_inAppScreenName, .second_inAppScreenName = *second_inAppScreenName};
return _friendsLaShow(&arg, playStartupSound);
}
Result friendsLaShowFriendList(AccountUid *userID) {
return _friendsLaShowSimple(FriendsLaArgType_ShowFriendList, userID, false);
}
Result friendsLaShowUserDetailInfo(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName) {
return _friendsLaShowAll(FriendsLaArgType_ShowUserDetailInfo, userID, networkServiceAccountId, first_inAppScreenName, second_inAppScreenName, false);
}
Result friendsLaStartSendingFriendRequest(AccountUid *userID, u64 networkServiceAccountId, const FriendsInAppScreenName *first_inAppScreenName, const FriendsInAppScreenName *second_inAppScreenName) {
return _friendsLaShowAll(FriendsLaArgType_StartSendingFriendRequest, userID, networkServiceAccountId, first_inAppScreenName, second_inAppScreenName, false);
}
Result friendsLaShowMethodsOfSendingFriendRequest(AccountUid *userID) {
return _friendsLaShowSimple(FriendsLaArgType_ShowMethodsOfSendingFriendRequest, userID, false);
}
Result friendsLaStartFacedFriendRequest(AccountUid *userID) {
return _friendsLaShowSimple(FriendsLaArgType_StartFacedFriendRequest, userID, false);
}
Result friendsLaShowReceivedFriendRequestList(AccountUid *userID) {
return _friendsLaShowSimple(FriendsLaArgType_ShowReceivedFriendRequestList, userID, false);
}
Result friendsLaShowBlockedUserList(AccountUid *userID) {
return _friendsLaShowSimple(FriendsLaArgType_ShowBlockedUserList, userID, false);
}
Result friendsLaShowMyProfile(AccountUid *userID) {
return _friendsLaShowSimple(FriendsLaArgType_ShowMyProfile, userID, false);
}
Result friendsLaShowMyProfileForHomeMenu(AccountUid *userID) {
return _friendsLaShowSimple(FriendsLaArgType_ShowMyProfile, userID, true);
}

View File

@ -350,11 +350,12 @@ Result webOfflineCreate(WebCommonConfig* config, WebDocumentKind docKind, u64 ti
Result webShareCreate(WebCommonConfig* config, WebShareStartPage page) { Result webShareCreate(WebCommonConfig* config, WebShareStartPage page) {
Result rc=0; Result rc=0;
AccountUid uid={0};
_webArgInitialize(config, AppletId_loginShare, WebShimKind_Share); _webArgInitialize(config, AppletId_loginShare, WebShimKind_Share);
rc = webConfigSetLeftStickMode(config, WebLeftStickMode_Cursor); rc = webConfigSetLeftStickMode(config, WebLeftStickMode_Cursor);
if (R_SUCCEEDED(rc)) rc = webConfigSetUserID(config, 0); if (R_SUCCEEDED(rc)) rc = webConfigSetUid(config, &uid);
if (R_SUCCEEDED(rc)) rc = webConfigSetDisplayUrlKind(config, true); if (R_SUCCEEDED(rc)) rc = webConfigSetDisplayUrlKind(config, true);
if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown14, 1); if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown14, 1);
@ -368,6 +369,7 @@ Result webShareCreate(WebCommonConfig* config, WebShareStartPage page) {
Result webLobbyCreate(WebCommonConfig* config) { Result webLobbyCreate(WebCommonConfig* config) {
Result rc=0; Result rc=0;
AccountUid uid={0};
if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
_webArgInitialize(config, AppletId_loginShare, WebShimKind_Lobby); _webArgInitialize(config, AppletId_loginShare, WebShimKind_Lobby);
@ -375,7 +377,7 @@ Result webLobbyCreate(WebCommonConfig* config) {
rc = webConfigSetLeftStickMode(config, WebLeftStickMode_Cursor); rc = webConfigSetLeftStickMode(config, WebLeftStickMode_Cursor);
if (R_SUCCEEDED(rc) && config->version >= 0x30000) rc = webConfigSetPointer(config, false); // Added to user-process init with [3.0.0+]. if (R_SUCCEEDED(rc) && config->version >= 0x30000) rc = webConfigSetPointer(config, false); // Added to user-process init with [3.0.0+].
if (R_SUCCEEDED(rc)) rc = webConfigSetUserID(config, 0); if (R_SUCCEEDED(rc)) rc = webConfigSetUid(config, &uid);
if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown14, 1); if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown14, 1);
if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown15, 1); if (R_SUCCEEDED(rc)) rc = _webConfigSetU8(config, WebArgType_Unknown15, 1);
@ -402,10 +404,10 @@ Result webConfigSetWhitelist(WebCommonConfig* config, const char* whitelist) {
return _webConfigSetString(config, WebArgType_Whitelist, whitelist, 0x1000); return _webConfigSetString(config, WebArgType_Whitelist, whitelist, 0x1000);
} }
Result webConfigSetUserID(WebCommonConfig* config, u128 userID) { Result webConfigSetUid(WebCommonConfig* config, AccountUid *uid) {
WebShimKind shim = _webGetShimKind(config); WebShimKind shim = _webGetShimKind(config);
if (shim != WebShimKind_Share && shim != WebShimKind_Web && shim != WebShimKind_Lobby) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); if (shim != WebShimKind_Share && shim != WebShimKind_Web && shim != WebShimKind_Lobby) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _webTLVSet(config, WebArgType_UserID, &userID, sizeof(userID)); return _webTLVSet(config, WebArgType_Uid, uid, sizeof(*uid));
} }
static Result _webConfigSetAlbumEntryTLV(WebCommonConfig* config, WebArgType type, const CapsAlbumEntry *entry) { static Result _webConfigSetAlbumEntryTLV(WebCommonConfig* config, WebArgType type, const CapsAlbumEntry *entry) {

View File

@ -5,11 +5,21 @@
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
#include "display/binder.h" #include "display/binder.h"
static void* _binderIpcPrepareHeader(Binder* b, IpcCommand* cmd, size_t sizeof_raw)
{
return serviceIpcPrepareHeader(b->relay, cmd, sizeof_raw);
}
static Result _binderIpcDispatch(Binder* b) static Result _binderIpcDispatch(Binder* b)
{ {
return serviceIpcDispatch(b->relay); return serviceIpcDispatch(b->relay);
} }
static Result _binderIpcParse(Binder* b, IpcParsedCommand* r, size_t sizeof_raw)
{
return serviceIpcParse(b->relay, r, sizeof_raw);
}
void binderCreate(Binder* b, s32 id) void binderCreate(Binder* b, s32 id)
{ {
memset(b, 0, sizeof(Binder)); memset(b, 0, sizeof(Binder));
@ -41,12 +51,6 @@ Result binderInitSession(Binder* b, Service* relay)
b->initialized = true; b->initialized = true;
rc = ipcQueryPointerBufferSize(b->relay->handle, &b->ipc_buffer_size);
if (R_FAILED(rc)) {
binderClose(b);
return rc;
}
// Use TransactParcelAuto when available. // Use TransactParcelAuto when available.
if (hosversionAtLeast(3,0,0)) if (hosversionAtLeast(3,0,0))
b->has_transact_auto = true; b->has_transact_auto = true;
@ -93,7 +97,7 @@ static Result _binderTransactParcel(
ipcAddSendBuffer(&c, parcel_data, parcel_data_size, 0); ipcAddSendBuffer(&c, parcel_data, parcel_data_size, 0);
ipcAddRecvBuffer(&c, parcel_reply, parcel_reply_size, 0); ipcAddRecvBuffer(&c, parcel_reply, parcel_reply_size, 0);
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 0; raw->cmd_id = 0;
raw->session_id = b->id; raw->session_id = b->id;
@ -104,12 +108,13 @@ static Result _binderTransactParcel(
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
ipcParse(&r);
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
} *resp = r.Raw; } *resp;
_binderIpcParse(b, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result; rc = resp->result;
} }
@ -137,10 +142,10 @@ static Result _binderTransactParcelAuto(
u32 flags; u32 flags;
} PACKED *raw; } PACKED *raw;
ipcAddSendSmart(&c, b->ipc_buffer_size, parcel_data, parcel_data_size, 0); ipcAddSendSmart(&c, b->relay->pointer_buffer_size, parcel_data, parcel_data_size, 0);
ipcAddRecvSmart(&c, b->ipc_buffer_size, parcel_reply, parcel_reply_size, 0); ipcAddRecvSmart(&c, b->relay->pointer_buffer_size, parcel_reply, parcel_reply_size, 0);
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 3; raw->cmd_id = 3;
raw->session_id = b->id; raw->session_id = b->id;
@ -151,12 +156,13 @@ static Result _binderTransactParcelAuto(
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
ipcParse(&r);
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
} *resp = r.Raw; } *resp;
_binderIpcParse(b, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result; rc = resp->result;
} }
@ -222,7 +228,7 @@ Result binderAdjustRefcount(Binder* b, s32 addval, s32 type)
s32 type; s32 type;
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 1; raw->cmd_id = 1;
raw->session_id = b->id; raw->session_id = b->id;
@ -233,12 +239,13 @@ Result binderAdjustRefcount(Binder* b, s32 addval, s32 type)
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
ipcParse(&r);
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
} *resp = r.Raw; } *resp;
_binderIpcParse(b, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result; rc = resp->result;
} }
@ -261,7 +268,7 @@ Result binderGetNativeHandle(Binder* b, u32 inval, Event *event_out)
u32 inval; u32 inval;
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 2; raw->cmd_id = 2;
@ -272,13 +279,14 @@ Result binderGetNativeHandle(Binder* b, u32 inval, Event *event_out)
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
ipcParse(&r);
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
} *resp = r.Raw; } *resp = r.Raw;
_binderIpcParse(b, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {

View File

@ -15,7 +15,7 @@ struct in_addr __nxlink_host;
extern char* fake_heap_start; extern char* fake_heap_start;
extern char* fake_heap_end; extern char* fake_heap_end;
extern u32 __argdata__; extern u8 __argdata__[];
static char* g_argv_empty = NULL; static char* g_argv_empty = NULL;
@ -27,7 +27,7 @@ void argvSetup(void)
MemoryInfo meminfo; MemoryInfo meminfo;
u32 pageinfo=0; u32 pageinfo=0;
u8 *argdata = (u8*)&__argdata__; u8 *argdata = __argdata__;
u32 *arg32 = (u32*)argdata; u32 *arg32 = (u32*)argdata;
u64 argdata_allocsize=0; u64 argdata_allocsize=0;
u64 argdata_strsize=0; u64 argdata_strsize=0;
@ -94,7 +94,7 @@ void argvSetup(void)
argstart = NULL; argstart = NULL;
for(argi=0; argi<argdata_strsize; argi++) { for(argi=0; argi<argdata_strsize; argi++) {
if (argstart == NULL && isspace(args[argi])) continue; if (argstart == NULL && isspace((unsigned char)args[argi])) continue;
if (argstart == NULL) { if (argstart == NULL) {
if (args[argi] == '"') { if (args[argi] == '"') {
@ -112,7 +112,7 @@ void argvSetup(void)
if (quote_flag) { if (quote_flag) {
if (args[argi] == '"') end_flag = 1; if (args[argi] == '"') end_flag = 1;
} }
else if (isspace(args[argi])) { else if (isspace((unsigned char)args[argi])) {
end_flag = 1; end_flag = 1;
} }

View File

@ -7,10 +7,12 @@
#include <sys/iosupport.h> #include <sys/iosupport.h>
#include <sys/param.h> #include <sys/param.h>
#include <unistd.h> #include <unistd.h>
#include <time.h>
#include "runtime/devices/fs_dev.h" #include "runtime/devices/fs_dev.h"
#include "runtime/util/utf.h" #include "runtime/util/utf.h"
#include "services/fs.h" #include "services/fs.h"
#include "services/time.h"
/*! @internal /*! @internal
@ -256,6 +258,28 @@ static ssize_t fsdev_convertfromfspath(uint8_t *out, uint8_t *in, size_t len)
return strnlen((char*)out, len); return strnlen((char*)out, len);
} }
static time_t fsdev_converttimetoutc(u64 timestamp)
{
// Parse timestamp into y/m/d h:m:s
time_t posixtime = (time_t)timestamp;
struct tm *t = gmtime(&posixtime);
// Convert time/date into an actual UTC POSIX timestamp using the system's timezone rules
TimeCalendarTime caltime;
caltime.year = 1900 + t->tm_year;
caltime.month = 1 + t->tm_mon;
caltime.day = t->tm_mday;
caltime.hour = t->tm_hour;
caltime.minute = t->tm_min;
caltime.second = t->tm_sec;
u64 new_timestamp;
Result rc = timeToPosixTimeWithMyRule(&caltime, &new_timestamp, 1, NULL);
if (R_SUCCEEDED(rc))
posixtime = (time_t)new_timestamp;
return posixtime;
}
extern int __system_argc; extern int __system_argc;
extern char** __system_argv; extern char** __system_argv;
@ -381,7 +405,7 @@ Result fsdevSetArchiveBit(const char *path) {
return fsFsSetArchiveBit(&device->fs, fs_path); return fsFsSetArchiveBit(&device->fs, fs_path);
} }
Result fsdevCreateFile(const char* path, size_t size, int flags) { Result fsdevCreateFile(const char* path, size_t size, u32 flags) {
char fs_path[FS_MAX_PATH]; char fs_path[FS_MAX_PATH];
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = NULL;
@ -555,7 +579,7 @@ fsdev_open(struct _reent *r,
{ {
/* read-only: do not allow O_APPEND */ /* read-only: do not allow O_APPEND */
case O_RDONLY: case O_RDONLY:
fsdev_flags |= FS_OPEN_READ; fsdev_flags |= FsOpenMode_Read;
if(flags & O_APPEND) if(flags & O_APPEND)
{ {
r->_errno = EINVAL; r->_errno = EINVAL;
@ -565,12 +589,12 @@ fsdev_open(struct _reent *r,
/* write-only */ /* write-only */
case O_WRONLY: case O_WRONLY:
fsdev_flags |= FS_OPEN_WRITE | FS_OPEN_APPEND; fsdev_flags |= FsOpenMode_Write | FsOpenMode_Append;
break; break;
/* read and write */ /* read and write */
case O_RDWR: case O_RDWR:
fsdev_flags |= (FS_OPEN_READ | FS_OPEN_WRITE | FS_OPEN_APPEND); fsdev_flags |= (FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
break; break;
/* an invalid option was supplied */ /* an invalid option was supplied */
@ -690,7 +714,7 @@ fsdev_write(struct _reent *r,
} }
} }
rc = fsFileWrite(&file->fd, file->offset, ptr, len, FS_WRITEOPTION_NONE); rc = fsFileWrite(&file->fd, file->offset, ptr, len, FsWriteOption_None);
if(rc == 0xD401) if(rc == 0xD401)
return fsdev_write_safe(r, fd, ptr, len); return fsdev_write_safe(r, fd, ptr, len);
if(R_FAILED(rc)) if(R_FAILED(rc))
@ -744,7 +768,7 @@ fsdev_write_safe(struct _reent *r,
memcpy(tmp_buffer, ptr, toWrite); memcpy(tmp_buffer, ptr, toWrite);
/* write the data */ /* write the data */
rc = fsFileWrite(&file->fd, file->offset, tmp_buffer, toWrite, FS_WRITEOPTION_NONE); rc = fsFileWrite(&file->fd, file->offset, tmp_buffer, toWrite, FsWriteOption_None);
if(R_FAILED(rc)) if(R_FAILED(rc))
{ {
@ -786,7 +810,7 @@ fsdev_read(struct _reent *r,
size_t len) size_t len)
{ {
Result rc; Result rc;
size_t bytes; u64 bytes;
/* get pointer to our data */ /* get pointer to our data */
fsdev_file_t *file = (fsdev_file_t*)fd; fsdev_file_t *file = (fsdev_file_t*)fd;
@ -799,7 +823,7 @@ fsdev_read(struct _reent *r,
} }
/* read the data */ /* read the data */
rc = fsFileRead(&file->fd, file->offset, ptr, len, FS_READOPTION_NONE, &bytes); rc = fsFileRead(&file->fd, file->offset, ptr, len, FsReadOption_None, &bytes);
if(rc == 0xD401) if(rc == 0xD401)
return fsdev_read_safe(r, fd, ptr, len); return fsdev_read_safe(r, fd, ptr, len);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
@ -830,7 +854,7 @@ fsdev_read_safe(struct _reent *r,
size_t len) size_t len)
{ {
Result rc; Result rc;
size_t bytesRead = 0, bytes = 0; u64 bytesRead = 0, bytes = 0;
/* get pointer to our data */ /* get pointer to our data */
fsdev_file_t *file = (fsdev_file_t*)fd; fsdev_file_t *file = (fsdev_file_t*)fd;
@ -841,12 +865,12 @@ fsdev_read_safe(struct _reent *r,
static __thread char tmp_buffer[8192]; static __thread char tmp_buffer[8192];
while(len > 0) while(len > 0)
{ {
size_t toRead = len; u64 toRead = len;
if(toRead > sizeof(tmp_buffer)) if(toRead > sizeof(tmp_buffer))
toRead = sizeof(tmp_buffer); toRead = sizeof(tmp_buffer);
/* read the data */ /* read the data */
rc = fsFileRead(&file->fd, file->offset, tmp_buffer, toRead, FS_READOPTION_NONE, &bytes); rc = fsFileRead(&file->fd, file->offset, tmp_buffer, toRead, FsReadOption_None, &bytes);
if(bytes > toRead) if(bytes > toRead)
bytes = toRead; bytes = toRead;
@ -965,9 +989,9 @@ fsdev_fstat(struct _reent *r,
if(file->timestamps.is_valid) if(file->timestamps.is_valid)
{ {
st->st_ctime = file->timestamps.created; st->st_ctime = fsdev_converttimetoutc(file->timestamps.created);
st->st_mtime = file->timestamps.modified; st->st_mtime = fsdev_converttimetoutc(file->timestamps.modified);
st->st_atime = file->timestamps.accessed; st->st_atime = fsdev_converttimetoutc(file->timestamps.accessed);
} }
return 0; return 0;
@ -998,7 +1022,7 @@ fsdev_stat(struct _reent *r,
char fs_path[FS_MAX_PATH]; char fs_path[FS_MAX_PATH];
fsdev_fsdevice *device = NULL; fsdev_fsdevice *device = NULL;
FsTimeStampRaw timestamps = {0}; FsTimeStampRaw timestamps = {0};
FsEntryType type; FsDirEntryType type;
if(fsdev_getfspath(r, file, &device, fs_path)==-1) if(fsdev_getfspath(r, file, &device, fs_path)==-1)
return -1; return -1;
@ -1006,9 +1030,9 @@ fsdev_stat(struct _reent *r,
rc = fsFsGetEntryType(&device->fs, fs_path, &type); rc = fsFsGetEntryType(&device->fs, fs_path, &type);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{ {
if(type == ENTRYTYPE_DIR) if(type == FsDirEntryType_Dir)
{ {
if(R_SUCCEEDED(rc = fsFsOpenDirectory(&device->fs, fs_path, FS_DIROPEN_DIRECTORY | FS_DIROPEN_FILE, &fdir))) if(R_SUCCEEDED(rc = fsFsOpenDirectory(&device->fs, fs_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &fdir)))
{ {
memset(st, 0, sizeof(struct stat)); memset(st, 0, sizeof(struct stat));
st->st_nlink = 1; st->st_nlink = 1;
@ -1017,9 +1041,9 @@ fsdev_stat(struct _reent *r,
return 0; return 0;
} }
} }
else if(type == ENTRYTYPE_FILE) else if(type == FsDirEntryType_File)
{ {
if(R_SUCCEEDED(rc = fsFsOpenFile(&device->fs, fs_path, FS_OPEN_READ, &fd))) if(R_SUCCEEDED(rc = fsFsOpenFile(&device->fs, fs_path, FsOpenMode_Read, &fd)))
{ {
fsdev_file_t tmpfd = { .fd = fd }; fsdev_file_t tmpfd = { .fd = fd };
ret = fsdev_fstat(r, &tmpfd, st); ret = fsdev_fstat(r, &tmpfd, st);
@ -1030,9 +1054,9 @@ fsdev_stat(struct _reent *r,
rc = fsFsGetFileTimeStampRaw(&device->fs, fs_path, &timestamps); rc = fsFsGetFileTimeStampRaw(&device->fs, fs_path, &timestamps);
if(R_SUCCEEDED(rc) && timestamps.is_valid) if(R_SUCCEEDED(rc) && timestamps.is_valid)
{ {
st->st_ctime = timestamps.created; st->st_ctime = fsdev_converttimetoutc(timestamps.created);
st->st_mtime = timestamps.modified; st->st_mtime = fsdev_converttimetoutc(timestamps.modified);
st->st_atime = timestamps.accessed; st->st_atime = fsdev_converttimetoutc(timestamps.accessed);
} }
} }
@ -1115,7 +1139,7 @@ fsdev_chdir(struct _reent *r,
if(fsdev_getfspath(r, name, &device, fs_path)==-1) if(fsdev_getfspath(r, name, &device, fs_path)==-1)
return -1; return -1;
rc = fsFsOpenDirectory(&device->fs, fs_path, FS_DIROPEN_DIRECTORY | FS_DIROPEN_FILE, &fd); rc = fsFsOpenDirectory(&device->fs, fs_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &fd);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{ {
fsDirClose(&fd); fsDirClose(&fd);
@ -1153,7 +1177,7 @@ fsdev_rename(struct _reent *r,
const char *newName) const char *newName)
{ {
Result rc; Result rc;
FsEntryType type; FsDirEntryType type;
fsdev_fsdevice *device_old = NULL, *device_new = NULL; fsdev_fsdevice *device_old = NULL, *device_new = NULL;
char fs_path_old[FS_MAX_PATH]; char fs_path_old[FS_MAX_PATH];
char fs_path_new[FS_MAX_PATH]; char fs_path_new[FS_MAX_PATH];
@ -1173,13 +1197,13 @@ fsdev_rename(struct _reent *r,
rc = fsFsGetEntryType(&device_old->fs, fs_path_old, &type); rc = fsFsGetEntryType(&device_old->fs, fs_path_old, &type);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{ {
if(type == ENTRYTYPE_DIR) if(type == FsDirEntryType_Dir)
{ {
rc = fsFsRenameDirectory(&device_old->fs, fs_path_old, fs_path_new); rc = fsFsRenameDirectory(&device_old->fs, fs_path_old, fs_path_new);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
return 0; return 0;
} }
else if(type == ENTRYTYPE_FILE) else if(type == FsDirEntryType_File)
{ {
rc = fsFsRenameFile(&device_old->fs, fs_path_old, fs_path_new); rc = fsFsRenameFile(&device_old->fs, fs_path_old, fs_path_new);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
@ -1251,7 +1275,7 @@ fsdev_diropen(struct _reent *r,
fsdev_dir_t *dir = (fsdev_dir_t*)(dirState->dirStruct); fsdev_dir_t *dir = (fsdev_dir_t*)(dirState->dirStruct);
/* open the directory */ /* open the directory */
rc = fsFsOpenDirectory(&device->fs, fs_path, FS_DIROPEN_DIRECTORY | FS_DIROPEN_FILE, &fd); rc = fsFsOpenDirectory(&device->fs, fs_path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles, &fd);
if(R_SUCCEEDED(rc)) if(R_SUCCEEDED(rc))
{ {
dir->magic = FSDEV_DIRITER_MAGIC; dir->magic = FSDEV_DIRITER_MAGIC;
@ -1299,7 +1323,7 @@ fsdev_dirnext(struct _reent *r,
struct stat *filestat) struct stat *filestat)
{ {
Result rc; Result rc;
size_t entries; u64 entries;
ssize_t units; ssize_t units;
FsDirectoryEntry *entry; FsDirectoryEntry *entry;
@ -1342,9 +1366,9 @@ fsdev_dirnext(struct _reent *r,
/* fill in the stat info */ /* fill in the stat info */
filestat->st_ino = 0; filestat->st_ino = 0;
if(entry->type == ENTRYTYPE_DIR) if(entry->type == FsDirEntryType_Dir)
filestat->st_mode = S_IFDIR; filestat->st_mode = S_IFDIR;
else if(entry->type == ENTRYTYPE_FILE) else if(entry->type == FsDirEntryType_File)
{ {
filestat->st_mode = S_IFREG; filestat->st_mode = S_IFREG;
filestat->st_size = entry->fileSize; filestat->st_size = entry->fileSize;

View File

@ -52,11 +52,11 @@ static char __thread __component[PATH_MAX+1];
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 size) static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 size)
{ {
u64 pos = mount->offset + offset; u64 pos = mount->offset + offset;
size_t read = 0; u64 read = 0;
Result rc = 0; Result rc = 0;
if(mount->fd_type == RomfsSource_FsFile) if(mount->fd_type == RomfsSource_FsFile)
{ {
rc = fsFileRead(&mount->fd, pos, buffer, size, FS_READOPTION_NONE, &read); rc = fsFileRead(&mount->fd, pos, buffer, size, FsReadOption_None, &read);
} }
else if(mount->fd_type == RomfsSource_FsStorage) else if(mount->fd_type == RomfsSource_FsStorage)
{ {
@ -170,7 +170,7 @@ static romfs_mount *romfsFindMount(const char *name)
} }
else if(mount->setup) //Find the mount with the input name. else if(mount->setup) //Find the mount with the input name.
{ {
if(strncmp(mount->name, name, strlen(mount->name))==0) if(strncmp(mount->name, name, sizeof(mount->name))==0)
return mount; return mount;
} }
} }
@ -244,7 +244,7 @@ Result romfsMount(const char *name)
return 2; return 2;
} }
Result rc = fsFsOpenFile(sdfs, filename, FS_OPEN_READ, &mount->fd); Result rc = fsFsOpenFile(sdfs, filename, FsOpenMode_Read, &mount->fd);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
romfs_free(mount); romfs_free(mount);
@ -344,7 +344,7 @@ Result romfsMountFromFsdev(const char *path, u64 offset, const char *name)
mount->fd_type = RomfsSource_FsFile; mount->fd_type = RomfsSource_FsFile;
mount->offset = offset; mount->offset = offset;
Result rc = fsFsOpenFile(tmpfs, filepath, FS_OPEN_READ, &mount->fd); Result rc = fsFsOpenFile(tmpfs, filepath, FsOpenMode_Read, &mount->fd);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
romfs_free(mount); romfs_free(mount);

View File

@ -5,6 +5,7 @@
#include "services/sm.h" #include "services/sm.h"
#include "services/fatal.h" #include "services/fatal.h"
#include "services/applet.h" #include "services/applet.h"
#include "services/acc.h"
void NORETURN __nx_exit(Result rc, LoaderReturnFn retaddr); void NORETURN __nx_exit(Result rc, LoaderReturnFn retaddr);
@ -23,7 +24,7 @@ static char* g_nextLoadArgv = NULL;
static Result g_lastLoadResult = 0; static Result g_lastLoadResult = 0;
static bool g_hasRandomSeed = false; static bool g_hasRandomSeed = false;
static u64 g_randomSeed[2] = { 0, 0 }; static u64 g_randomSeed[2] = { 0, 0 };
static u128* g_userIdStorage = NULL; static AccountUid* g_userIdStorage = NULL;
extern __attribute__((weak)) u32 __nx_applet_type; extern __attribute__((weak)) u32 __nx_applet_type;
@ -104,7 +105,7 @@ void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr)
break; break;
case EntryType_UserIdStorage: case EntryType_UserIdStorage:
g_userIdStorage = (u128*)(uintptr_t)ent->Value[0]; g_userIdStorage = (AccountUid*)(uintptr_t)ent->Value[0];
break; break;
case EntryType_HosVersion: case EntryType_HosVersion:
@ -222,6 +223,6 @@ void envGetRandomSeed(u64 out[2]) {
out[1] = g_randomSeed[1]; out[1] = g_randomSeed[1];
} }
u128* envGetUserIdStorage(void) { AccountUid* envGetUserIdStorage(void) {
return g_userIdStorage; return g_userIdStorage;
} }

View File

@ -29,7 +29,7 @@ static u32 g_nacpLanguageTable[15] = {
Result nacpGetLanguageEntry(NacpStruct* nacp, NacpLanguageEntry** langentry) { Result nacpGetLanguageEntry(NacpStruct* nacp, NacpLanguageEntry** langentry) {
Result rc=0; Result rc=0;
u64 LanguageCode=0; u64 LanguageCode=0;
s32 Language=0; SetLanguage Language=0;
NacpLanguageEntry *entry = NULL; NacpLanguageEntry *entry = NULL;
u32 i=0; u32 i=0;

View File

@ -1,37 +1,44 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h> #include <string.h>
#include "service_guard.h"
#include "types.h"
#include "arm/atomics.h"
#include "services/acc.h" #include "services/acc.h"
#include "services/sm.h"
#include "services/applet.h" #include "services/applet.h"
#include "runtime/env.h" #include "runtime/env.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
static AccountServiceType g_accServiceType = AccountServiceType_NotInitialized;
static Service g_accSrv; static Service g_accSrv;
static u64 g_refCnt; static AccountUid g_accPreselectedUserID;
static u128 g_accPreselectedUserID;
static bool g_accPreselectedUserInitialized; static bool g_accPreselectedUserInitialized;
static Result _accountInitializeApplicationInfo(void); static Result _accountInitializeApplicationInfo(void);
static Result _accountGetPreselectedUser(u128 *userID); static Result _accountGetPreselectedUser(AccountUid *userID);
Result accountInitialize(void) NX_GENERATE_SERVICE_GUARD(account);
{
void accountSetServiceType(AccountServiceType serviceType) {
g_accServiceType = serviceType;
}
Result _accountInitialize(void) {
Result rc=0; Result rc=0;
Result rc2=0; Result rc2=0;
u128 *userIdEnv = envGetUserIdStorage(); AccountUid *userIdEnv = envGetUserIdStorage();
atomicIncrement64(&g_refCnt); switch (g_accServiceType) {
case AccountServiceType_NotInitialized:
if (serviceIsActive(&g_accSrv)) case AccountServiceType_Application:
return 0; g_accServiceType = AccountServiceType_Application;
rc = smGetService(&g_accSrv, "acc:u0");
rc = smGetService(&g_accSrv, "acc:u1"); if (R_SUCCEEDED(rc)) rc = _accountInitializeApplicationInfo();
if (R_FAILED(rc)) { break;
rc = smGetService(&g_accSrv, "acc:u0"); case AccountServiceType_System:
if (R_SUCCEEDED(rc)) rc = _accountInitializeApplicationInfo(); rc = smGetService(&g_accSrv, "acc:u1");
break;
case AccountServiceType_Administrator:
rc = smGetService(&g_accSrv, "acc:su");
break;
} }
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
@ -42,354 +49,128 @@ Result accountInitialize(void)
} }
else if (userIdEnv) { else if (userIdEnv) {
g_accPreselectedUserID = *userIdEnv; g_accPreselectedUserID = *userIdEnv;
if (g_accPreselectedUserID) g_accPreselectedUserInitialized = true; if (accountUidIsValid(&g_accPreselectedUserID)) g_accPreselectedUserInitialized = true;
} }
} }
if (R_FAILED(rc)) accountExit();
return rc; return rc;
} }
void accountExit(void) void _accountCleanup(void) {
{ serviceClose(&g_accSrv);
if (atomicDecrement64(&g_refCnt) == 0) g_accServiceType = AccountServiceType_NotInitialized;
serviceClose(&g_accSrv);
} }
Service* accountGetServiceSession(void) { Service* accountGetServiceSession(void) {
return &g_accSrv; return &g_accSrv;
} }
static Result _accountCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _accountInitializeApplicationInfo(void) { static Result _accountInitializeApplicationInfo(void) {
IpcCommand c; u64 pid_placeholder=0;
ipcInitialize(&c); return serviceDispatchIn(&g_accSrv, hosversionBefore(6,0,0) ? 100 : 140, pid_placeholder,
.in_send_pid = true,
struct { );
u64 magic;
u64 cmd_id;
u64 pid_placeholder;
} *raw;
ipcSendPid(&c);
raw = serviceIpcPrepareHeader(&g_accSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionBefore(6,0,0) ? 100 : 140;
raw->pid_placeholder = 0;
Result rc = serviceIpcDispatch(&g_accSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_accSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result accountGetUserCount(s32* user_count) Result accountGetUserCount(s32* user_count) {
{ return _accountCmdNoInOutU32(&g_accSrv, (u32*)user_count, 0);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&g_accSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 user_count;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*user_count = resp->user_count;
}
}
return rc;
} }
static Result _accountListAllUsers(u128* userIDs) static Result _accountListAllUsers(AccountUid* userIDs) {
{ return serviceDispatch(&g_accSrv, 2,
IpcCommand c; .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out },
ipcInitialize(&c); .buffers = { { userIDs, sizeof(AccountUid)*ACC_USER_LIST_SIZE } },
);
}
Result accountListAllUsers(AccountUid* userIDs, s32 max_userIDs, s32 *actual_total) {
Result rc=0; Result rc=0;
AccountUid temp_userIDs[ACC_USER_LIST_SIZE];
size_t bufsize = ACC_USER_LIST_SIZE * sizeof(u128);
ipcAddRecvStatic(&c, userIDs, bufsize, 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2;
rc = serviceIpcDispatch(&g_accSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result accountListAllUsers(u128* userIDs, size_t max_userIDs, size_t *actual_total)
{
Result rc=0;
u128 temp_userIDs[ACC_USER_LIST_SIZE];
memset(temp_userIDs, 0, sizeof(temp_userIDs)); memset(temp_userIDs, 0, sizeof(temp_userIDs));
rc = _accountListAllUsers(temp_userIDs); rc = _accountListAllUsers(temp_userIDs);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
size_t total_userIDs; s32 total_userIDs;
for (total_userIDs = 0; total_userIDs < ACC_USER_LIST_SIZE; total_userIDs++) { for (total_userIDs=0; total_userIDs<ACC_USER_LIST_SIZE; total_userIDs++) {
if (!temp_userIDs[total_userIDs]) if (!accountUidIsValid(&temp_userIDs[total_userIDs])) break;
break;
} }
if (max_userIDs > total_userIDs) { if (max_userIDs > total_userIDs) {
max_userIDs = total_userIDs; max_userIDs = total_userIDs;
} }
memcpy(userIDs, temp_userIDs, sizeof(u128) * max_userIDs); memcpy(userIDs, temp_userIDs, sizeof(AccountUid)*max_userIDs);
*actual_total = max_userIDs; *actual_total = max_userIDs;
} }
return rc; return rc;
} }
Result accountGetLastOpenedUser(u128 *userID, bool *account_selected) Result accountGetLastOpenedUser(AccountUid *userID) {
{ return serviceDispatchOut(&g_accSrv, 4, *userID);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 4;
Result rc = serviceIpcDispatch(&g_accSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u128 userID;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && userID) {
*userID = resp->userID;
if (account_selected) {
*account_selected = 0;
if (*userID != 0) *account_selected = 1;
}
}
}
return rc;
} }
Result accountGetProfile(AccountProfile* out, u128 userID) { Result accountGetProfile(AccountProfile* out, const AccountUid *userID) {
IpcCommand c; return serviceDispatchIn(&g_accSrv, 5, *userID,
ipcInitialize(&c); .out_num_objects = 1,
.out_objects = &out->s,
struct { );
u64 magic;
u64 cmd_id;
u128 userID;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
raw->userID = userID;
Result rc = serviceIpcDispatch(&g_accSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(&out->s, r.Handles[0]);
}
}
return rc;
} }
//IProfile implementation // IProfile
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
IpcCommand c;
ipcInitialize(&c);
if (userdata) ipcAddRecvStatic(&c, userdata, sizeof(AccountUserData), 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = userdata==NULL ? 1 : 0;
Result rc = serviceIpcDispatch(&profile->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
AccountProfileBase profilebase;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && profilebase) memcpy(profilebase, &resp->profilebase, sizeof(AccountProfileBase));
}
return rc;
}
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 10;
Result rc = serviceIpcDispatch(&profile->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 image_size;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*image_size = resp->image_size;
}
}
return rc;
}
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, buf, len, 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 11;
Result rc = serviceIpcDispatch(&profile->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 image_size;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*image_size = resp->image_size;
}
}
return rc;
}
void accountProfileClose(AccountProfile* profile) { void accountProfileClose(AccountProfile* profile) {
serviceClose(&profile->s); serviceClose(&profile->s);
} }
static Result _accountGetPreselectedUser(u128 *userID) { static Result _accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
return serviceDispatchOut(&profile->s, 0, *profilebase,
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
.buffers = { { userdata, sizeof(AccountUserData) } },
);
}
static Result _accountProfileGetBase(AccountProfile* profile, AccountProfileBase* profilebase) {
return serviceDispatchOut(&profile->s, 1, *profilebase);
}
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
Result rc=0;
if (!serviceIsActive(&profile->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (userdata)
rc = _accountProfileGet(profile, userdata, profilebase);
else
rc = _accountProfileGetBase(profile, profilebase);
return rc;
}
Result accountProfileGetImageSize(AccountProfile* profile, u32* image_size) {
if (!serviceIsActive(&profile->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _accountCmdNoInOutU32(&profile->s, image_size, 10);
}
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, u32* image_size) {
if (!serviceIsActive(&profile->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return serviceDispatchOut(&profile->s, 11, *image_size,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { buf, len } },
);
}
static Result _accountGetPreselectedUser(AccountUid *userID) {
Result rc=0; Result rc=0;
AppletStorage storage; AppletStorage storage;
s64 tmpsize=0; s64 tmpsize=0;
@ -398,9 +179,9 @@ static Result _accountGetPreselectedUser(u128 *userID) {
u32 magicnum;//These two fields must match fixed values. u32 magicnum;//These two fields must match fixed values.
u8 unk_x4; u8 unk_x4;
u8 pad[3]; u8 pad[3];
u128 userID; AccountUid userID;
u8 unk_x18[0x70];//unused u8 unk_x18[0x70];//unused
} PACKED storagedata; } storagedata;
memset(&storagedata, 0, sizeof(storagedata)); memset(&storagedata, 0, sizeof(storagedata));
@ -424,7 +205,7 @@ static Result _accountGetPreselectedUser(u128 *userID) {
return rc; return rc;
} }
Result accountGetPreselectedUser(u128 *userID) { Result accountGetPreselectedUser(AccountUid *userID) {
if (!g_accPreselectedUserInitialized) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); if (!g_accPreselectedUserInitialized) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
*userID = g_accPreselectedUserID; *userID = g_accPreselectedUserID;

View File

@ -1,153 +1,55 @@
#include "types.h" #define NX_SERVICE_ASSUME_NON_DOMAIN
#include "result.h" #include "service_guard.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "services/apm.h" #include "services/apm.h"
#include "services/sm.h"
static Service g_apmSrv; static Service g_apmSrv;
static Service g_apmISession; static Service g_apmISession;
static u64 g_refCnt;
static Result _apmGetSession(Service* srv, Service* srv_out, u64 cmd_id); static Result _apmCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id);
Result apmInitialize(void) NX_GENERATE_SERVICE_GUARD(apm);
{
atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_apmSrv)) Result _apmInitialize(void) {
return 0; Result rc = smGetService(&g_apmSrv, "apm");
Result rc = 0;
rc = smGetService(&g_apmSrv, "apm");
// OpenSession. // OpenSession.
// Official sw doesn't open this until using commands which need it, when it wasn't already opened. // Official sw doesn't open this until using commands which need it, when it wasn't already opened.
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc)) rc = _apmCmdGetSession(&g_apmSrv, &g_apmISession, 0);
rc = _apmGetSession(&g_apmSrv, &g_apmISession, 0);
if (R_FAILED(rc))
apmExit();
return rc; return rc;
} }
void apmExit(void) void _apmCleanup(void) {
{ serviceClose(&g_apmISession);
if (atomicDecrement64(&g_refCnt) == 0) { serviceClose(&g_apmSrv);
serviceClose(&g_apmISession);
serviceClose(&g_apmSrv);
}
} }
Service* apmGetServiceSession(void) { Service* apmGetServiceSession(void) {
return &g_apmSrv; return &g_apmSrv;
} }
static Result _apmGetSession(Service* srv, Service* srv_out, u64 cmd_id) { Service* apmGetServiceSession_Session(void) {
IpcCommand c; return &g_apmISession;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(srv_out, r.Handles[0]);
}
}
return rc;
} }
Result apmSetPerformanceConfiguration(u32 PerformanceMode, u32 PerformanceConfiguration) { static Result _apmCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
IpcCommand c; return serviceDispatch(srv, cmd_id,
ipcInitialize(&c); .out_num_objects = 1,
.out_objects = srv_out,
);
}
struct { Result apmSetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 PerformanceConfiguration) {
u64 magic; const struct {
u64 cmd_id;
u32 PerformanceMode; u32 PerformanceMode;
u32 PerformanceConfiguration; u32 PerformanceConfiguration;
} *raw; } in = { PerformanceMode, PerformanceConfiguration };
raw = ipcPrepareHeader(&c, sizeof(*raw)); return serviceDispatchIn(&g_apmISession, 0, in);
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->PerformanceMode = PerformanceMode;
raw->PerformanceConfiguration = PerformanceConfiguration;
Result rc = serviceIpcDispatch(&g_apmISession);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result apmGetPerformanceConfiguration(u32 PerformanceMode, u32 *PerformanceConfiguration) { Result apmGetPerformanceConfiguration(ApmPerformanceMode PerformanceMode, u32 *PerformanceConfiguration) {
IpcCommand c; u32 tmp=PerformanceMode;
ipcInitialize(&c); return serviceDispatchInOut(&g_apmISession, 1, tmp, *PerformanceConfiguration);
struct {
u64 magic;
u64 cmd_id;
u32 PerformanceMode;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->PerformanceMode = PerformanceMode;
Result rc = serviceIpcDispatch(&g_apmISession);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 PerformanceConfiguration;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && PerformanceConfiguration) *PerformanceConfiguration = resp->PerformanceConfiguration;
}
return rc;
} }

File diff suppressed because it is too large Load Diff

115
nx/source/services/async.c Normal file
View File

@ -0,0 +1,115 @@
#include "sf/service.h"
#include "runtime/hosversion.h"
#include "services/async.h"
#include "applets/error.h"
static Result _asyncCmdNoIO(Service* srv, u32 cmd_id) {
return serviceDispatch(srv, cmd_id);
}
static Result _asyncCmdNoInOutU64(Service* srv, u64 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _asyncCmdNoInOutBuf(Service* srv, void* buffer, size_t size, u32 cmd_id) {
return serviceDispatch(srv, cmd_id,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { buffer, size } },
);
}
// IAsyncValue
void asyncValueClose(AsyncValue *a) {
if (serviceIsActive(&a->s)) {
asyncValueCancel(a); // Official sw ignores rc from this prior to waiting on the event.
asyncValueWait(a, U64_MAX);
}
serviceClose(&a->s);
eventClose(&a->event);
}
Result asyncValueWait(AsyncValue *a, u64 timeout) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return eventWait(&a->event, timeout);
}
Result asyncValueGetSize(AsyncValue *a, u64 *size) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _asyncCmdNoInOutU64(&a->s, size, 0);
}
Result asyncValueGet(AsyncValue *a, void* buffer, size_t size) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
Result rc = asyncValueWait(a, U64_MAX);
if (R_SUCCEEDED(rc)) rc = _asyncCmdNoInOutBuf(&a->s, buffer, size, 1);
return rc;
}
Result asyncValueCancel(AsyncValue *a) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _asyncCmdNoIO(&a->s, 2);
}
Result asyncValueGetErrorContext(AsyncValue *a, ErrorContext *context) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _asyncCmdNoInOutBuf(&a->s, context, sizeof(*context), 3);
}
// AsyncResult
void asyncResultClose(AsyncResult *a) {
if (serviceIsActive(&a->s)) {
asyncResultCancel(a); // Official sw ignores rc from this prior to waiting on the event.
asyncResultWait(a, U64_MAX);
}
serviceClose(&a->s);
eventClose(&a->event);
}
Result asyncResultWait(AsyncResult *a, u64 timeout) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return eventWait(&a->event, timeout);
}
Result asyncResultGet(AsyncResult *a) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
Result rc = asyncResultWait(a, U64_MAX);
if (R_SUCCEEDED(rc)) rc = _asyncCmdNoIO(&a->s, 0);
return rc;
}
Result asyncResultCancel(AsyncResult *a) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _asyncCmdNoIO(&a->s, 1);
}
Result asyncResultGetErrorContext(AsyncResult *a, ErrorContext *context) {
if (!serviceIsActive(&a->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _asyncCmdNoInOutBuf(&a->s, context, sizeof(*context), 2);
}

View File

@ -11,7 +11,6 @@
static Service g_auddevIAudioDevice; static Service g_auddevIAudioDevice;
static u64 g_auddevRefCnt; static u64 g_auddevRefCnt;
static size_t g_auddevIpcBufferSize;
static Result _auddevGetAudioDeviceService(Service* srv, Service* out_srv, u64 aruid); static Result _auddevGetAudioDeviceService(Service* srv, Service* out_srv, u64 aruid);
@ -32,8 +31,6 @@ Result auddevInitialize(void) {
rc = _auddevGetAudioDeviceService(&audrenMgrSrv, &g_auddevIAudioDevice, aruid); rc = _auddevGetAudioDeviceService(&audrenMgrSrv, &g_auddevIAudioDevice, aruid);
serviceClose(&audrenMgrSrv); serviceClose(&audrenMgrSrv);
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_auddevIAudioDevice.handle, &g_auddevIpcBufferSize);
} }
if (R_FAILED(rc)) auddevExit(); if (R_FAILED(rc)) auddevExit();
@ -102,7 +99,7 @@ Result auddevListAudioDeviceName(AudioDeviceName *DeviceNames, s32 max_names, s3
} *raw; } *raw;
if (!new_cmd) ipcAddRecvBuffer(&c, DeviceNames, sizeof(AudioDeviceName) * max_names, BufferType_Normal); if (!new_cmd) ipcAddRecvBuffer(&c, DeviceNames, sizeof(AudioDeviceName) * max_names, BufferType_Normal);
if (new_cmd) ipcAddRecvSmart(&c, g_auddevIpcBufferSize, DeviceNames, sizeof(AudioDeviceName) * max_names, 0); if (new_cmd) ipcAddRecvSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceNames, sizeof(AudioDeviceName) * max_names, 0);
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw)); raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
@ -144,7 +141,7 @@ Result auddevSetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float
} *raw; } *raw;
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal); if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0); if (new_cmd) ipcAddSendSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceName, sizeof(AudioDeviceName), 0);
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw)); raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
@ -183,7 +180,7 @@ Result auddevGetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float
} *raw; } *raw;
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal); if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0); if (new_cmd) ipcAddSendSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceName, sizeof(AudioDeviceName), 0);
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw)); raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));

View File

@ -24,7 +24,6 @@ __thread Result g_bsdResult;
__thread int g_bsdErrno; __thread int g_bsdErrno;
static Service g_bsdSrv; static Service g_bsdSrv;
static size_t g_bsdSrvIpcBufferSize;
static Service g_bsdMonitor; static Service g_bsdMonitor;
static u64 g_bsdClientPid = -1; static u64 g_bsdClientPid = -1;
@ -189,7 +188,7 @@ static int _bsdNameGetterCommand(u32 cmd_id, int sockfd, struct sockaddr *addr,
socklen_t maxaddrlen = addrlen == NULL ? 0 : *addrlen; socklen_t maxaddrlen = addrlen == NULL ? 0 : *addrlen;
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, addr, maxaddrlen, 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, addr, maxaddrlen, 0);
struct { struct {
u64 magic; u64 magic;
@ -247,9 +246,6 @@ Result bsdInitialize(const BsdInitConfig *config) {
} }
if(R_FAILED(rc)) goto error; if(R_FAILED(rc)) goto error;
rc = ipcQueryPointerBufferSize(g_bsdSrv.handle, &g_bsdSrvIpcBufferSize);
if(R_FAILED(rc)) goto error;
rc = smGetService(&g_bsdMonitor, bsd_srv); rc = smGetService(&g_bsdMonitor, bsd_srv);
if(R_FAILED(rc)) goto error; if(R_FAILED(rc)) goto error;
@ -270,7 +266,6 @@ error:
} }
void bsdExit(void) { void bsdExit(void) {
g_bsdSrvIpcBufferSize = 0;
g_bsdClientPid = 0; g_bsdClientPid = 0;
serviceClose(&g_bsdMonitor); serviceClose(&g_bsdMonitor);
serviceClose(&g_bsdSrv); serviceClose(&g_bsdSrv);
@ -294,7 +289,7 @@ int bsdOpen(const char *pathname, int flags) {
ipcInitialize(&c); ipcInitialize(&c);
size_t pathlen = strlen(pathname) + 1; size_t pathlen = strlen(pathname) + 1;
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, pathname, pathlen, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, pathname, pathlen, 0);
struct { struct {
u64 magic; u64 magic;
@ -315,15 +310,15 @@ int bsdSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, st
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
struct { struct {
@ -349,8 +344,8 @@ int bsdPoll(struct pollfd *fds, nfds_t nfds, int timeout) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, fds, nfds * sizeof(struct pollfd), 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, fds, nfds * sizeof(struct pollfd), 0);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, fds, nfds * sizeof(struct pollfd), 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, fds, nfds * sizeof(struct pollfd), 0);
struct { struct {
u64 magic; u64 magic;
@ -375,10 +370,10 @@ int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, name, 4 * namelen, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, name, 4 * namelen, 0);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, newp, newlen, 1); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, newp, newlen, 1);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, oldp, inlen, 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, oldp, inlen, 0);
struct { struct {
u64 magic; u64 magic;
@ -405,7 +400,7 @@ int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp
ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags) { ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
struct { struct {
u64 magic; u64 magic;
@ -430,8 +425,8 @@ ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockadd
ipcInitialize(&c); ipcInitialize(&c);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, src_addr, inaddrlen, 1); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, src_addr, inaddrlen, 1);
struct { struct {
u64 magic; u64 magic;
@ -453,7 +448,7 @@ ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockadd
ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) { ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
struct { struct {
u64 magic; u64 magic;
@ -475,8 +470,8 @@ ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) {
ssize_t bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { ssize_t bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, dest_addr, addrlen, 1); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, dest_addr, addrlen, 1);
struct { struct {
u64 magic; u64 magic;
@ -502,7 +497,7 @@ int bsdAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, addr, addrlen, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, addr, addrlen, 0);
struct { struct {
u64 magic; u64 magic;
@ -522,7 +517,7 @@ int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, addr, addrlen, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, addr, addrlen, 0);
struct { struct {
u64 magic; u64 magic;
@ -553,7 +548,7 @@ int bsdGetSockOpt(int sockfd, int level, int optname, void *optval, socklen_t *o
socklen_t inoptlen = optlen == NULL ? 0 : *optlen; socklen_t inoptlen = optlen == NULL ? 0 : *optlen;
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, optval, inoptlen, 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, optval, inoptlen, 0);
struct { struct {
u64 magic; u64 magic;
@ -645,15 +640,15 @@ int bsdIoctl(int fd, int request, void *data) {
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in1, in1sz, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in1, in1sz, 0);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in2, in2sz, 1); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in2, in2sz, 1);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in3, in3sz, 2); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in3, in3sz, 2);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in4, in4sz, 3); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in4, in4sz, 3);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out1, out1sz, 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out1, out1sz, 0);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out2, out2sz, 1); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out2, out2sz, 1);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out3, out3sz, 2); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out3, out3sz, 2);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out4, out4sz, 3); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out4, out4sz, 3);
struct { struct {
u64 magic; u64 magic;
@ -711,7 +706,7 @@ int bsdSetSockOpt(int sockfd, int level, int optname, const void *optval, sockle
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, optval, optlen, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, optval, optlen, 0);
struct { struct {
u64 magic; u64 magic;
@ -775,7 +770,7 @@ int bsdShutdownAllSockets(int how) {
ssize_t bsdWrite(int fd, const void *buf, size_t count) { ssize_t bsdWrite(int fd, const void *buf, size_t count) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, count, 0); ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, count, 0);
struct { struct {
u64 magic; u64 magic;
@ -795,7 +790,7 @@ ssize_t bsdWrite(int fd, const void *buf, size_t count) {
ssize_t bsdRead(int fd, void *buf, size_t count) { ssize_t bsdRead(int fd, void *buf, size_t count) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, count, 0); ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, count, 0);
struct { struct {
u64 magic; u64 magic;

17
nx/source/services/caps.c Normal file
View File

@ -0,0 +1,17 @@
#include <string.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "kernel/event.h"
#include "kernel/tmem.h"
#include "services/sm.h"
#include "services/caps.h"
#include "runtime/hosversion.h"
u64 capsGetShimLibraryVersion(void) {
u64 version=1; // [7.0.0-8.1.0]
return version;
}

View File

@ -1,85 +1,45 @@
#include "types.h" #define NX_SERVICE_ASSUME_NON_DOMAIN
#include "result.h" #include "service_guard.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
#include "services/caps.h" #include "services/caps.h"
#include "services/capssc.h" #include "services/capssc.h"
#include "services/sm.h"
static Service g_capsscSrv; static Service g_capsscSrv;
static u64 g_capsscRefCnt;
Result capsscInitialize(void) { NX_GENERATE_SERVICE_GUARD(capssc);
Result _capsscInitialize(void) {
Result rc=0; Result rc=0;
atomicIncrement64(&g_capsscRefCnt);
if (serviceIsActive(&g_capsscSrv))
return 0;
if (hosversionBefore(2,0,0)) if (hosversionBefore(2,0,0))
rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
if (R_SUCCEEDED(rc)) rc = smGetService(&g_capsscSrv, "caps:sc"); if (R_SUCCEEDED(rc)) rc = smGetService(&g_capsscSrv, "caps:sc");
if (R_FAILED(rc)) capsscExit();
return rc; return rc;
} }
void capsscExit(void) { void _capsscCleanup(void) {
if (atomicDecrement64(&g_capsscRefCnt) == 0) serviceClose(&g_capsscSrv);
serviceClose(&g_capsscSrv);
} }
Service* capsscGetServiceSession(void) { Service* capsscGetServiceSession(void) {
return &g_capsscSrv; return &g_capsscSrv;
} }
Result capsscCaptureScreenshot(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout) { Result capsscCaptureRawImageWithTimeout(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout) {
IpcCommand c; const struct {
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 inval; u32 inval;
u64 width; u64 width;
u64 height; u64 height;
s64 buffer_count; s64 buffer_count;
s64 buffer_index; s64 buffer_index;
u64 timeout; u64 timeout;
} *raw; } in = { inval, width, height, buffer_count, buffer_index, timeout };
ipcAddRecvBuffer(&c, buf, size, 1); return serviceDispatchIn(&g_capsscSrv, 2, in,
.buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
raw = serviceIpcPrepareHeader(&g_capsscSrv, &c, sizeof(*raw)); .buffers = { { buf, size } },
);
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2;
raw->inval = inval;
raw->width = width;
raw->height = height;
raw->buffer_count = buffer_count;
raw->buffer_index = buffer_index;
raw->timeout = timeout;
Result rc = serviceIpcDispatch(&g_capsscSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_capsscSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }

View File

@ -1,101 +1,157 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h> #include <string.h>
#include "types.h" #include "service_guard.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
#include "services/applet.h" #include "services/applet.h"
#include "services/caps.h" #include "services/caps.h"
#include "services/capssu.h" #include "services/capssu.h"
#include "services/sm.h" #include "services/acc.h"
static Service g_capssuSrv; static Service g_capssuSrv;
static u64 g_capssuRefCnt;
Result capssuInitialize(void) { static Result _capssuSetShimLibraryVersion(u64 version);
NX_GENERATE_SERVICE_GUARD(capssu);
Result _capssuInitialize(void) {
Result rc=0; Result rc=0;
atomicIncrement64(&g_capssuRefCnt);
if (serviceIsActive(&g_capssuSrv))
return 0;
if (hosversionBefore(4,0,0)) if (hosversionBefore(4,0,0))
rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
if (R_SUCCEEDED(rc)) rc = smGetService(&g_capssuSrv, "caps:su"); if (R_SUCCEEDED(rc)) rc = smGetService(&g_capssuSrv, "caps:su");
if (R_FAILED(rc)) capssuExit(); if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _capssuSetShimLibraryVersion(capsGetShimLibraryVersion());
return rc; return rc;
} }
void capssuExit(void) { void _capssuCleanup(void) {
if (atomicDecrement64(&g_capssuRefCnt) == 0) serviceClose(&g_capssuSrv);
serviceClose(&g_capssuSrv);
} }
Service* capssuGetServiceSession(void) { Service* capssuGetServiceSession(void) {
return &g_capssuSrv; return &g_capssuSrv;
} }
static Result _capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out) { static Result _capssuSetShimLibraryVersion(u64 version) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u64 AppletResourceUserId = 0; u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId); appletGetAppletResourceUserId(&AppletResourceUserId);
IpcCommand c; const struct {
ipcInitialize(&c); u64 version;
struct {
u64 magic;
u64 cmd_id;
CapsScreenShotAttribute attr;
u32 unk;
u64 AppletResourceUserId; u64 AppletResourceUserId;
} *raw; } in = { version, AppletResourceUserId };
ipcSendPid(&c); return serviceDispatchIn(&g_capssuSrv, 32, in,
ipcAddSendBuffer(&c, buffer, size, 1); .in_send_pid = true,
);
raw = serviceIpcPrepareHeader(&g_capssuSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 203;
raw->attr = *attr;
raw->unk = unk;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_capssuSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
CapsApplicationAlbumEntry out;
} *resp;
serviceIpcParse(&g_capssuSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) *out = resp->out;
}
return rc;
} }
Result capssuSaveScreenShot(const void* buffer, size_t size, u32 unk, u32 attr_val, CapsApplicationAlbumEntry *out) { static Result _capssuSaveScreenShotEx0(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
CapsScreenShotAttribute attr;
u32 reportoption;
u64 AppletResourceUserId;
} in = { *attr, reportoption, AppletResourceUserId };
return serviceDispatchInOut(&g_capssuSrv, 203, in, *out,
.buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { buffer, size } },
.in_send_pid = true,
);
}
static Result _capssuSaveScreenShotEx(u32 cmd_id, bool pid, const void* argbuf, size_t argbuf_size, const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
CapsScreenShotAttribute attr;
u32 reportoption;
u64 AppletResourceUserId;
} in = { *attr, reportoption, AppletResourceUserId };
return serviceDispatchInOut(&g_capssuSrv, cmd_id, in, *out,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
},
.buffers = {
{ argbuf, argbuf_size },
{ buffer, size },
},
.in_send_pid = pid,
);
}
Result capssuSaveScreenShot(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, CapsApplicationAlbumEntry *out) {
CapsScreenShotAttribute attr; CapsScreenShotAttribute attr;
memset(&attr, 0, sizeof(attr)); memset(&attr, 0, sizeof(attr));
attr.unk_x0 = attr_val; attr.orientation = orientation;
attr.unk_xc = 1;
return _capssuSaveScreenShotEx0(buffer, size, &attr, unk, out); return _capssuSaveScreenShotEx0(buffer, size, &attr, reportoption, out);
} }
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, CapsScreenShotAttribute *attr, u32 unk, CapsApplicationAlbumEntry *out) { Result capssuSaveScreenShotWithUserData(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const void* userdata, size_t userdata_size, CapsApplicationAlbumEntry *out) {
return _capssuSaveScreenShotEx0(buffer, size, attr, unk, out); CapsScreenShotAttribute attr;
CapsApplicationData appdata;
if (userdata_size > sizeof(appdata).userdata)
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
memset(&attr, 0, sizeof(attr));
attr.orientation = orientation;
attr.unk_xc = 1;
memset(&appdata, 0, sizeof(appdata));
if (userdata && userdata_size) memcpy(appdata.userdata, userdata, userdata_size);
appdata.size = userdata_size;
return capssuSaveScreenShotEx1(buffer, size, &attr, reportoption, &appdata, out);
}
Result capssuSaveScreenShotWithUserIds(const void* buffer, size_t size, AlbumReportOption reportoption, AlbumImageOrientation orientation, const AccountUid* userIDs, size_t userID_count, CapsApplicationAlbumEntry *out) {
CapsScreenShotAttribute attr;
CapsUserIdList list;
if (userID_count > ACC_USER_LIST_SIZE)
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
memset(&attr, 0, sizeof(attr));
attr.orientation = orientation;
attr.unk_xc = 1;
memset(&list, 0, sizeof(list));
if (userIDs && userID_count) memcpy(list.userIDs, userIDs, userID_count*sizeof(AccountUid));
list.count = userID_count;
return capssuSaveScreenShotEx2(buffer, size, &attr, reportoption, &list, out);
}
Result capssuSaveScreenShotEx0(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationAlbumEntry *out) {
return _capssuSaveScreenShotEx0(buffer, size, attr, reportoption, out);
}
Result capssuSaveScreenShotEx1(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsApplicationData *appdata, CapsApplicationAlbumEntry *out) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _capssuSaveScreenShotEx(205, true, appdata, sizeof(*appdata), buffer, size, attr, reportoption, out);
}
Result capssuSaveScreenShotEx2(const void* buffer, size_t size, const CapsScreenShotAttribute *attr, AlbumReportOption reportoption, CapsUserIdList *list, CapsApplicationAlbumEntry *out) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _capssuSaveScreenShotEx(210, false, list, sizeof(*list), buffer, size, attr, reportoption, out);
} }

380
nx/source/services/capsu.c Normal file
View File

@ -0,0 +1,380 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h>
#include <time.h>
#include "service_guard.h"
#include "runtime/hosversion.h"
#include "services/applet.h"
#include "services/caps.h"
#include "services/capsu.h"
#include "services/acc.h"
static Service g_capsuSrv;
static Service g_capsuAccessor;
static Result _capsuSetShimLibraryVersion(u64 version);
NX_GENERATE_SERVICE_GUARD(capsu);
Result _capsuInitialize(void) {
Result rc=0;
if (hosversionBefore(5,0,0))
rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
if (R_SUCCEEDED(rc)) rc = smGetService(&g_capsuSrv, "caps:u");
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _capsuSetShimLibraryVersion(capsGetShimLibraryVersion());
return rc;
}
void _capsuCleanup(void) {
serviceClose(&g_capsuAccessor);
serviceClose(&g_capsuSrv);
}
Service* capsuGetServiceSession(void) {
return &g_capsuSrv;
}
Service* capsuGetServiceSession_Accessor(void) {
return &g_capsuAccessor;
}
static Result _capsuCmdInU64NoOut(Service* srv, u64 inval, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, inval);
}
static Result _capsuSetShimLibraryVersion(u64 version) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
u64 version;
u64 AppletResourceUserId;
} in = { version, AppletResourceUserId };
return serviceDispatchIn(&g_capsuSrv, 32, in,
.in_send_pid = true,
);
}
static Result _capsuGetAlbumFileList0AafeAruidDeprecated(void* entries, size_t entrysize, s32 count, u8 type, u64 start_timestamp, u64 end_timestamp, s32 *total_entries) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
u8 type;
u64 start_timestamp;
u64 end_timestamp;
u64 AppletResourceUserId;
} in = { type, start_timestamp, end_timestamp, AppletResourceUserId };
u64 total_out=0;
Result rc = serviceDispatchInOut(&g_capsuSrv, 102, in, total_out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { entries, count*entrysize } },
.in_send_pid = true,
);
if (R_SUCCEEDED(rc) && total_entries) *total_entries = total_out;
return rc;
}
static Result _capsuDeleteAlbumFileByAruid(u32 cmd_id, u8 type, const CapsApplicationAlbumFileEntry *entry) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
u8 type;
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} in = { type, *entry, AppletResourceUserId };
return serviceDispatchIn(&g_capsuSrv, 103, in,
.in_send_pid = true,
);
}
static Result _capsuGetAlbumFileSizeByAruid(const CapsApplicationAlbumFileEntry *entry, u64 *size) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} in = { *entry, AppletResourceUserId };
return serviceDispatchInOut(&g_capsuSrv, 104, in, *size,
.in_send_pid = true,
);
}
static Result _capsuPrecheckToCreateContentsByAruid(u8 type, u64 unk) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
u8 type;
u64 unk;
u64 AppletResourceUserId;
} in = { type, unk, AppletResourceUserId };
return serviceDispatchIn(&g_capsuSrv, 130, in,
.in_send_pid = true,
);
}
static Result _capsuLoadAlbumScreenShotImageByAruid(u32 cmd_id, CapsLoadAlbumScreenShotImageOutputForApplication *out, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
CapsApplicationAlbumFileEntry entry;
CapsScreenShotDecodeOption option;
u64 AppletResourceUserId;
} in = { *entry, *option, AppletResourceUserId };
return serviceDispatchIn(&g_capsuSrv, cmd_id, in,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
},
.buffers = {
{ out, sizeof(*out) },
{ image, image_size },
{ workbuf, workbuf_size },
},
.in_send_pid = true,
);
}
static Result _capsuGetAlbumFileListAaeAruid(u32 cmd_id, void* entries, size_t entrysize, s32 count, u8 type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
u8 type;
CapsAlbumFileDateTime start_datetime;
CapsAlbumFileDateTime end_datetime;
u64 AppletResourceUserId;
} in = { type, *start_datetime, *end_datetime, AppletResourceUserId };
u64 total_out=0;
Result rc = serviceDispatchInOut(&g_capsuSrv, cmd_id, in, total_out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { entries, count*entrysize } },
.in_send_pid = true,
);
if (R_SUCCEEDED(rc) && total_entries) *total_entries = total_out;
return rc;
}
static Result _capsuGetAlbumFileListAaeUidAruid(u32 cmd_id, void* entries, size_t entrysize, s32 count, u8 type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
u8 type;
CapsAlbumFileDateTime start_datetime;
CapsAlbumFileDateTime end_datetime;
AccountUid userID;
u64 AppletResourceUserId;
} in = { type, *start_datetime, *end_datetime, *userID, AppletResourceUserId };
u64 total_out=0;
Result rc = serviceDispatchInOut(&g_capsuSrv, cmd_id, in, total_out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { entries, count*entrysize } },
.in_send_pid = true,
);
if (R_SUCCEEDED(rc) && total_entries) *total_entries = total_out;
return rc;
}
static Result _capsuOpenAccessorSessionForApplication(Service* srv_out, const CapsApplicationAlbumFileEntry *entry) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} in = { *entry, AppletResourceUserId };
return serviceDispatchIn(&g_capsuSrv, 60002, in,
.in_send_pid = true,
.out_num_objects = 1,
.out_objects = srv_out,
);
}
static Result _capsuOpenAlbumMovieReadStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry) {
u64 AppletResourceUserId = 0;
appletGetAppletResourceUserId(&AppletResourceUserId);
const struct {
CapsApplicationAlbumFileEntry entry;
u64 AppletResourceUserId;
} in = { *entry, AppletResourceUserId };
return serviceDispatchInOut(&g_capsuAccessor, 2001, in, *stream,
.in_send_pid = true,
);
}
static Result _capsuGetAlbumMovieReadStreamMovieDataSize(u64 stream, u64 *size) {
return serviceDispatchInOut(&g_capsuAccessor, 2003, stream, *size);
}
static Result _capsuReadMovieDataFromAlbumMovieReadStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) {
const struct {
u64 stream;
s64 offset;
} in = { stream, offset };
return serviceDispatchInOut(&g_capsuAccessor, 2004, in, *actual_size,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { buffer, size } },
);
}
static inline u64 _capsuMakeTimestamp(const CapsAlbumFileDateTime *datetime) {
struct tm tmptm = {.tm_sec = datetime->second, .tm_min = datetime->minute, .tm_hour = datetime->hour,
.tm_mday = datetime->day, .tm_mon = datetime->month, .tm_year = datetime->year - 1900};
return mktime(&tmptm);
}
Result capsuGetAlbumFileListDeprecated1(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries) {
u64 start_timestamp = 0x386BF200;
u64 end_timestamp = 0xF4865700;
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
if (hosversionBefore(6,0,0)) { // GetAlbumFileListDeprecated0
if (start_datetime) start_timestamp = _capsuMakeTimestamp(start_datetime);
if (end_datetime) end_timestamp = _capsuMakeTimestamp(end_datetime);
return _capsuGetAlbumFileList0AafeAruidDeprecated(entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_timestamp, end_timestamp, total_entries);
}
return _capsuGetAlbumFileListAaeAruid(140, entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, total_entries);
}
Result capsuGetAlbumFileListDeprecated2(CapsApplicationAlbumFileEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
return _capsuGetAlbumFileListAaeUidAruid(141, entries, sizeof(CapsApplicationAlbumFileEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, userID, total_entries);
}
Result capsuGetAlbumFileList3(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, s32 *total_entries) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
return _capsuGetAlbumFileListAaeAruid(142, entries, sizeof(CapsApplicationAlbumEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, total_entries);
}
Result capsuGetAlbumFileList4(CapsApplicationAlbumEntry *entries, s32 count, CapsContentType type, const CapsAlbumFileDateTime *start_datetime, const CapsAlbumFileDateTime *end_datetime, AccountUid *userID, s32 *total_entries) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
CapsAlbumFileDateTime default_start = capsGetDefaultStartDateTime();
CapsAlbumFileDateTime default_end = capsGetDefaultEndDateTime();
return _capsuGetAlbumFileListAaeUidAruid(143, entries, sizeof(CapsApplicationAlbumEntry), count, type, start_datetime ? start_datetime : &default_start, end_datetime ? end_datetime : &default_end, userID, total_entries);
}
Result capsuDeleteAlbumFile(CapsContentType type, const CapsApplicationAlbumFileEntry *entry) {
return _capsuDeleteAlbumFileByAruid(103, type, entry);
}
Result capsuGetAlbumFileSize(const CapsApplicationAlbumFileEntry *entry, u64 *size) {
return _capsuGetAlbumFileSizeByAruid(entry, size);
}
static void _capsuProcessImageOutput(CapsLoadAlbumScreenShotImageOutputForApplication *out, s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size) {
if (out==NULL) return;
if (width) *width = out->width;
if (height) *height = out->height;
if (attr) memcpy(attr, &out->attr, sizeof(out->attr));
if (userdata && userdata_maxsize) {
memset(userdata, 0, userdata_maxsize);
if (userdata_maxsize > sizeof(out->appdata.userdata)) userdata_maxsize = sizeof(out->appdata.userdata);
if (userdata_maxsize > out->appdata.size) userdata_maxsize = out->appdata.size;
memcpy(userdata, out->appdata.userdata, userdata_maxsize);
}
if (userdata_size) *userdata_size = out->appdata.size > sizeof(out->appdata.userdata) ? sizeof(out->appdata.userdata) : out->appdata.size;
}
Result capsuLoadAlbumScreenShotImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
Result rc=0;
CapsLoadAlbumScreenShotImageOutputForApplication out={0};
rc = _capsuLoadAlbumScreenShotImageByAruid(110, &out, image, image_size, workbuf, workbuf_size, entry, option);
if (R_SUCCEEDED(rc)) _capsuProcessImageOutput(&out, width, height, attr, userdata, userdata_maxsize, userdata_size);
return rc;
}
Result capsuLoadAlbumScreenShotThumbnailImage(s32 *width, s32 *height, CapsScreenShotAttributeForApplication *attr, void* userdata, size_t userdata_maxsize, u32 *userdata_size, void* image, size_t image_size, void* workbuf, size_t workbuf_size, const CapsApplicationAlbumFileEntry *entry, const CapsScreenShotDecodeOption *option) {
Result rc=0;
CapsLoadAlbumScreenShotImageOutputForApplication out={0};
rc = _capsuLoadAlbumScreenShotImageByAruid(120, &out, image, image_size, workbuf, workbuf_size, entry, option);
if (R_SUCCEEDED(rc)) _capsuProcessImageOutput(&out, width, height, attr, userdata, userdata_maxsize, userdata_size);
return rc;
}
Result capsuPrecheckToCreateContents(CapsContentType type, u64 unk) {
return _capsuPrecheckToCreateContentsByAruid(type, unk);
}
Result capsuOpenAlbumMovieStream(u64 *stream, const CapsApplicationAlbumFileEntry *entry) {
Result rc=0;
if (!serviceIsActive(&g_capsuAccessor)) rc =_capsuOpenAccessorSessionForApplication(&g_capsuAccessor, entry);
if (R_SUCCEEDED(rc)) rc = _capsuOpenAlbumMovieReadStream(stream, entry);
return rc;
}
Result capsuCloseAlbumMovieStream(u64 stream) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuCmdInU64NoOut(&g_capsuAccessor, stream, 2002);
}
Result capsuGetAlbumMovieStreamSize(u64 stream, u64 *size) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuGetAlbumMovieReadStreamMovieDataSize(stream, size);
}
Result capsuReadAlbumMovieStream(u64 stream, s64 offset, void* buffer, size_t size, u64 *actual_size) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuReadMovieDataFromAlbumMovieReadStream(stream, offset, buffer, size, actual_size);
}
Result capsuGetAlbumMovieStreamBrokenReason(u64 stream) {
if (!serviceIsActive(&g_capsuAccessor))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _capsuCmdInU64NoOut(&g_capsuAccessor, stream, 2005);
}

View File

@ -1,28 +1,17 @@
// Copyright 2018 SciresM #define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h> #include "service_guard.h"
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "services/csrng.h" #include "services/csrng.h"
#include "services/sm.h"
#include "services/spl.h"
static Service g_csrngSrv; static Service g_csrngSrv;
static u64 g_csrngRefCnt;
Result csrngInitialize(void) { NX_GENERATE_SERVICE_GUARD(csrng);
atomicIncrement64(&g_csrngRefCnt);
Result _csrngInitialize(void) {
if (serviceIsActive(&g_csrngSrv))
return 0;
return smGetService(&g_csrngSrv, "csrng"); return smGetService(&g_csrngSrv, "csrng");
} }
void csrngExit(void) { void _csrngCleanup(void) {
if (atomicDecrement64(&g_csrngRefCnt) == 0) serviceClose(&g_csrngSrv);
serviceClose(&g_csrngSrv);
} }
Service* csrngGetServiceSession(void) { Service* csrngGetServiceSession(void) {
@ -30,34 +19,8 @@ Service* csrngGetServiceSession(void) {
} }
Result csrngGetRandomBytes(void *out, size_t out_size) { Result csrngGetRandomBytes(void *out, size_t out_size) {
IpcCommand c; return serviceDispatch(&g_csrngSrv, 0,
ipcInitialize(&c); .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out, out_size } },
ipcAddRecvBuffer(&c, out, out_size, BufferType_Normal); );
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&g_csrngSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }

View File

@ -1,9 +1,10 @@
// Copyright 2017 plutoo // Copyright 2017 plutoo
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include "types.h" #include "types.h"
#include "result.h" #include "result.h"
#include "kernel/ipc.h"
#include "kernel/detect.h" #include "kernel/detect.h"
#include "kernel/svc.h" #include "kernel/svc.h"
#include "sf/service.h"
#include "services/fatal.h" #include "services/fatal.h"
#include "services/sm.h" #include "services/sm.h"
@ -17,42 +18,30 @@ static void _fatalImpl(u32 cmd_id, Result err, FatalType type, FatalContext *ctx
svcBreak(0x80000000, err, 0); svcBreak(0x80000000, err, 0);
} }
if (!smHasInitialized()) { Handle session;
rc = smInitialize(); rc = smInitialize();
if (R_SUCCEEDED(rc)) {
rc = smGetServiceOriginal(&session, smEncodeName("fatal:u"));
smExit();
} }
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
Handle srv; const struct {
rc = smGetServiceOriginal(&srv, smEncodeName("fatal:u")); u32 result;
u32 type;
u64 pid_placeholder;
} in = { err, type };
if (R_SUCCEEDED(rc)) { Service s;
IpcCommand c; serviceCreate(&s, session);
ipcInitialize(&c); serviceDispatchIn(&s, cmd_id, in,
ipcSendPid(&c); .buffer_attrs = { ctx ? (SfBufferAttr_In | SfBufferAttr_HipcMapAlias) : 0U },
if (ctx != NULL) { .buffers = { { ctx, sizeof(*ctx) } },
ipcAddSendBuffer(&c, ctx, sizeof(*ctx), BufferType_Normal); .in_send_pid = true,
} );
serviceClose(&s);
struct {
u64 magic;
u64 cmd_id;
u32 result;
u32 type;
u64 pid_placeholder;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->result = err;
raw->type = type;
raw->pid_placeholder = 0; // Overwritten by fatal with PID descriptor.
ipcDispatch(srv);
}
} }
switch (type) { switch (type) {
case FatalType_ErrorReport: case FatalType_ErrorReport:
break; break;
@ -72,7 +61,7 @@ void NORETURN fatalSimple(Result err) {
} }
void fatalWithType(Result err, FatalType type) { void fatalWithType(Result err, FatalType type) {
_fatalImpl(1, err, type, NULL); _fatalImpl(1, err, type, NULL);
} }
void fatalWithContext(Result err, FatalType type, FatalContext *ctx) { void fatalWithContext(Result err, FatalType type, FatalContext *ctx) {

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +1,32 @@
// Copyright 2018 SciresM // Copyright 2018 SciresM
#include <string.h> #include <string.h>
#include "types.h" #include "service_guard.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
#include "services/fs.h" #include "services/fs.h"
#include "services/sm.h"
#include "services/fsldr.h" #include "services/fsldr.h"
static Service g_fsldrSrv; static Service g_fsldrSrv;
static u64 g_fsldrRefCnt;
Result fsldrSetCurrentProcess(void); NX_GENERATE_SERVICE_GUARD(fsldr);
Result fsldrInitialize(void) { NX_INLINE Result _fsldrSetCurrentProcess(void);
atomicIncrement64(&g_fsldrRefCnt);
if (serviceIsActive(&g_fsldrSrv))
return 0;
Result _fsldrInitialize(void) {
Result rc = smGetService(&g_fsldrSrv, "fsp-ldr"); Result rc = smGetService(&g_fsldrSrv, "fsp-ldr");
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
rc = serviceConvertToDomain(&g_fsldrSrv); rc = serviceConvertToDomain(&g_fsldrSrv);
} }
if (R_SUCCEEDED(rc) && hosversionAtLeast(4,0,0)) { if (R_SUCCEEDED(rc) && hosversionAtLeast(4,0,0)) {
rc = fsldrSetCurrentProcess(); rc = _fsldrSetCurrentProcess();
} }
return rc; return rc;
} }
void fsldrExit(void) { void _fsldrCleanup(void) {
if (atomicDecrement64(&g_fsldrRefCnt) == 0) serviceClose(&g_fsldrSrv);
serviceClose(&g_fsldrSrv);
} }
Service* fsldrGetServiceSession(void) { Service* fsldrGetServiceSession(void) {
@ -44,115 +34,25 @@ Service* fsldrGetServiceSession(void) {
} }
Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out) { Result fsldrOpenCodeFileSystem(u64 tid, const char *path, FsFileSystem* out) {
char send_path[FS_MAX_PATH+1] = {0}; char send_path[FS_MAX_PATH + 1];
IpcCommand c;
ipcInitialize(&c);
ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0);
struct {
u64 magic;
u64 cmd_id;
u64 tid;
} *raw;
raw = serviceIpcPrepareHeader(&g_fsldrSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->tid = tid;
strncpy(send_path, path, FS_MAX_PATH); strncpy(send_path, path, FS_MAX_PATH);
Result rc = serviceIpcDispatch(&g_fsldrSrv); return serviceDispatchIn(&g_fsldrSrv, 0, tid,
.buffer_attrs = {
if (R_SUCCEEDED(rc)) { SfBufferAttr_HipcPointer | SfBufferAttr_In,
IpcParsedCommand r; },
struct { .buffers = {
u64 magic; { send_path, FS_MAX_PATH },
u64 result; },
} *resp; .out_num_objects = 1,
.out_objects = &out->s,
serviceIpcParse(&g_fsldrSrv, &r, sizeof(*resp)); );
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreateSubservice(&out->s, &g_fsldrSrv, &r, 0);
}
}
return rc;
} }
Result fsldrIsArchivedProgram(u64 pid, bool *out) { Result fsldrIsArchivedProgram(u64 pid, bool *out) {
IpcCommand c; return serviceDispatchInOut(&g_fsldrSrv, 1, pid, *out);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
} *raw;
raw = serviceIpcPrepareHeader(&g_fsldrSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->pid = pid;
Result rc = serviceIpcDispatch(&g_fsldrSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u8 is_archived;
} *resp;
serviceIpcParse(&g_fsldrSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*out = resp->is_archived != 0;
}
}
return rc;
} }
Result fsldrSetCurrentProcess(void) { Result _fsldrSetCurrentProcess(void) {
IpcCommand c; u64 pid_placeholder = 0;
ipcInitialize(&c); return serviceDispatchIn(&g_fsldrSrv, 2, pid_placeholder, .in_send_pid = true);
ipcSendPid(&c);
struct {
u64 magic;
u64 cmd_id;
u64 unk;
} *raw;
raw = serviceIpcPrepareHeader(&g_fsldrSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2;
raw->unk = 0;
Result rc = serviceIpcDispatch(&g_fsldrSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_fsldrSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }

View File

@ -7,7 +7,10 @@
#include "kernel/tmem.h" #include "kernel/tmem.h"
#include "services/sm.h" #include "services/sm.h"
#include "services/grc.h" #include "services/grc.h"
#include "services/caps.h"
#include "services/applet.h" #include "services/applet.h"
#include "display/native_window.h"
#include "audio/audio.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
static void _grcGameMovieTrimmerClose(GrcGameMovieTrimmer *t); static void _grcGameMovieTrimmerClose(GrcGameMovieTrimmer *t);
@ -44,6 +47,114 @@ static Result _grcCmdNoIO(Service* srv, u64 cmd_id) {
return rc; return rc;
} }
static Result _grcCmdInU64(Service* srv, u64 inval, u64 cmd_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 inval;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->inval = inval;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _grcCmdInU64Out32(Service* srv, u64 inval, u32 *out, u64 cmd_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 inval;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->inval = inval;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 out;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) *out = resp->out;
}
return rc;
}
static Result _grcCmdNoInOut64(Service* srv, u64 *out, u64 cmd_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 out;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) {
*out = resp->out;
}
}
return rc;
}
static Result _grcGetEvent(Service* srv, Event* out_event, u64 cmd_id, bool autoclear) { static Result _grcGetEvent(Service* srv, Event* out_event, u64 cmd_id, bool autoclear) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
@ -80,6 +191,80 @@ static Result _grcGetEvent(Service* srv, Event* out_event, u64 cmd_id, bool auto
return rc; return rc;
} }
static Result _grcCmdInU64OutEvent(Service* srv, u64 inval, Event* out_event, u64 cmd_id, bool autoclear) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 inval;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->inval = inval;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
eventLoadRemote(out_event, r.Handles[0], autoclear);
}
}
return rc;
}
static Result _grcGetSession(Service* srv, Service* srv_out, u64 cmd_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreateSubservice(srv_out, srv, &r, 0);
}
}
return rc;
}
static Result _grcCreateGameMovieTrimmer(GrcGameMovieTrimmer *t, size_t size) { static Result _grcCreateGameMovieTrimmer(GrcGameMovieTrimmer *t, size_t size) {
Result rc=0; Result rc=0;
Result retryrc = MAKERESULT(212, 4); Result retryrc = MAKERESULT(212, 4);
@ -260,6 +445,314 @@ Result grcTrimGameMovie(GrcGameMovieId *dst_movieid, const GrcGameMovieId *src_m
return rc; return rc;
} }
// IMovieMaker
void grcCreateOffscreenRecordingParameter(GrcOffscreenRecordingParameter *param) {
memset(param, 0, sizeof(*param));
param->unk_x10 = 0x103;
param->video_bitrate = 8000000;
param->video_width = 1280;
param->video_height = 720;
param->video_framerate = 30;
param->video_keyFrameInterval = 30;
param->audio_bitrate = hosversionAtLeast(6,0,0) ? 128000 : 1536000;
param->audio_samplerate = 48000;
param->audio_channel_count = 2;
param->audio_sample_format = PcmFormat_Int16;
param->video_imageOrientation = AlbumImageOrientation_Unknown0;
}
Result grcCreateMovieMaker(GrcMovieMaker *m, size_t size) {
Result rc=0;
Result retryrc = MAKERESULT(212, 4);
s32 binder_id=0;
memset(m, 0, sizeof(*m));
rc = tmemCreate(&m->tmem, size, Perm_None);
if (R_SUCCEEDED(rc)) {
rc = appletCreateMovieMaker(&m->a, &m->tmem);
while(rc == retryrc) {
svcSleepThread(100000000);
rc = appletCreateMovieMaker(&m->a, &m->tmem);
}
}
if (R_SUCCEEDED(rc)) rc = _grcGetSession(&m->a, &m->s, 0); // GetGrcMovieMaker
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) rc = _grcCmdInU64(&m->s, capsGetShimLibraryVersion(), 9); // SetAlbumShimLibraryVersion
if (R_SUCCEEDED(rc)) rc = _grcCmdNoInOut64(&m->a, &m->layer_handle, 1); // GetLayerHandle
if (R_SUCCEEDED(rc)) rc = _grcGetSession(&m->s, &m->video_proxy, 2); // CreateVideoProxy
if (R_SUCCEEDED(rc)) rc = _grcCmdInU64Out32(&m->s, m->layer_handle, (u32*)&binder_id, 10); // OpenOffscreenLayer
if (R_SUCCEEDED(rc)) m->layer_open = true;
if (R_SUCCEEDED(rc)) rc = nwindowCreate(&m->win, &m->video_proxy, binder_id, false);
if (R_SUCCEEDED(rc)) rc = nwindowSetDimensions(&m->win, 1280, 720);
if (R_SUCCEEDED(rc)) rc = _grcCmdInU64OutEvent(&m->s, m->layer_handle, &m->recording_event, 50, false); // GetOffscreenLayerRecordingFinishReadyEvent
if (R_SUCCEEDED(rc)) rc = _grcCmdInU64OutEvent(&m->s, m->layer_handle, &m->audio_event, 52, false); // GetOffscreenLayerAudioEncodeReadyEvent
if (R_FAILED(rc)) grcMovieMakerClose(m);
return rc;
}
void grcMovieMakerClose(GrcMovieMaker *m) {
grcMovieMakerAbort(m);
eventClose(&m->audio_event);
eventClose(&m->recording_event);
nwindowClose(&m->win);
if (m->layer_open) {
_grcCmdInU64(&m->s, m->layer_handle, 11); // CloseOffscreenLayer
m->layer_open = false;
}
serviceClose(&m->video_proxy);
serviceClose(&m->s);
serviceClose(&m->a);
tmemClose(&m->tmem);
}
Result grcMovieMakerStart(GrcMovieMaker *m, const GrcOffscreenRecordingParameter *param) {
if (!serviceIsActive(&m->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 layer_handle;
GrcOffscreenRecordingParameter param;
} *raw;
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 24;
raw->layer_handle = m->layer_handle;
memcpy(&raw->param, param, sizeof(GrcOffscreenRecordingParameter));
Result rc = serviceIpcDispatch(&m->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&m->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
if (R_SUCCEEDED(rc)) m->started_flag = true;
return rc;
}
Result grcMovieMakerAbort(GrcMovieMaker *m) {
Result rc=0;
if (!serviceIsActive(&m->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (!m->started_flag)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
rc = _grcCmdInU64(&m->s, m->layer_handle, 21); // AbortOffscreenRecording
if (R_SUCCEEDED(rc)) m->started_flag = false;
return rc;
}
static Result _grcMovieMakerCompleteOffscreenRecordingFinishEx0(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size) {
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, userdata, userdata_size, BufferType_Normal);
ipcAddSendBuffer(&c, thumbnail, thumbnail_size, BufferType_Normal);
struct {
u64 magic;
u64 cmd_id;
s32 width;
s32 height;
u64 layer_handle;
} *raw;
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 25;
raw->width = width;
raw->height = height;
raw->layer_handle = m->layer_handle;
Result rc = serviceIpcDispatch(&m->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
CapsApplicationAlbumEntry entry;
} *resp;
serviceIpcParse(&m->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _grcMovieMakerCompleteOffscreenRecordingFinishEx1(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size, CapsApplicationAlbumEntry *entry) {
if (hosversionBefore(7,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, userdata, userdata_size, BufferType_Normal);
ipcAddSendBuffer(&c, thumbnail, thumbnail_size, BufferType_Normal);
struct {
u64 magic;
u64 cmd_id;
s32 width;
s32 height;
u64 layer_handle;
} *raw;
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 26;
raw->width = width;
raw->height = height;
raw->layer_handle = m->layer_handle;
Result rc = serviceIpcDispatch(&m->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
CapsApplicationAlbumEntry entry;
} *resp;
serviceIpcParse(&m->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && entry) *entry = resp->entry;
}
return rc;
}
Result grcMovieMakerFinish(GrcMovieMaker *m, s32 width, s32 height, const void* userdata, size_t userdata_size, const void* thumbnail, size_t thumbnail_size, CapsApplicationAlbumEntry *entry) {
Result rc=0;
if (!serviceIsActive(&m->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(7,0,0) && entry)
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
rc = _grcCmdInU64(&m->s, m->layer_handle, 22); // RequestOffscreenRecordingFinishReady
if (R_SUCCEEDED(rc)) rc = eventWait(&m->recording_event, U64_MAX);
if (hosversionAtLeast(7,0,0))
rc = _grcMovieMakerCompleteOffscreenRecordingFinishEx1(m, width, height, userdata, userdata_size, thumbnail, thumbnail_size, entry);
else
rc = _grcMovieMakerCompleteOffscreenRecordingFinishEx0(m, width, height, userdata, userdata_size, thumbnail, thumbnail_size);
if (R_FAILED(rc)) grcMovieMakerAbort(m);
return rc;
}
Result grcMovieMakerGetError(GrcMovieMaker *m) {
if (!serviceIsActive(&m->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _grcCmdInU64(&m->s, m->layer_handle, 30); // GetOffscreenLayerError
}
static Result _grcMovieMakerEncodeOffscreenLayerAudioSample(GrcMovieMaker *m, const void* buffer, size_t size, u64 *out_size) {
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, buffer, size, BufferType_Normal);
struct {
u64 magic;
u64 cmd_id;
u64 layer_handle;
} *raw;
raw = serviceIpcPrepareHeader(&m->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 41;
raw->layer_handle = m->layer_handle;
Result rc = serviceIpcDispatch(&m->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 out_size;
} *resp;
serviceIpcParse(&m->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out_size) *out_size = resp->out_size;
}
return rc;
}
Result grcMovieMakerEncodeAudioSample(GrcMovieMaker *m, const void* buffer, size_t size) {
Result rc=0;
u64 out_size=0;
u8 *bufptr = (u8*)buffer;
if (!serviceIsActive(&m->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
for (u64 pos=0; size!=0; pos+=out_size, size-=out_size) {
rc = eventWait(&m->audio_event, U64_MAX);
if (R_FAILED(rc)) break;
rc = _grcMovieMakerEncodeOffscreenLayerAudioSample(m, &bufptr[pos], size, &out_size);
if (R_FAILED(rc)) break;
if (out_size > size) out_size = size;
}
return rc;
}
// grc:d // grc:d
static Service g_grcdSrv; static Service g_grcdSrv;

View File

@ -97,7 +97,7 @@ Result hidInitialize(void)
rc = _hidActivateNpad(); rc = _hidActivateNpad();
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = hidSetSupportedNpadStyleSet(TYPE_PROCONTROLLER | TYPE_HANDHELD | TYPE_JOYCON_PAIR | TYPE_JOYCON_LEFT | TYPE_JOYCON_RIGHT); rc = hidSetSupportedNpadStyleSet(TYPE_PROCONTROLLER | TYPE_HANDHELD | TYPE_JOYCON_PAIR | TYPE_JOYCON_LEFT | TYPE_JOYCON_RIGHT | TYPE_SYSTEM_EXT | TYPE_SYSTEM);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = hidSetSupportedNpadIdType(idbuf, 9); rc = hidSetSupportedNpadIdType(idbuf, 9);
@ -1032,11 +1032,11 @@ Result hidSetNpadJoyHoldType(HidJoyHoldType type) {
} }
Result hidSetNpadJoyAssignmentModeSingleByDefault(HidControllerID id) { Result hidSetNpadJoyAssignmentModeSingleByDefault(HidControllerID id) {
return _hidCmdWithInputU32(122, id); return _hidCmdWithInputU32(122, hidControllerIDToOfficial(id));
} }
Result hidSetNpadJoyAssignmentModeDual(HidControllerID id) { Result hidSetNpadJoyAssignmentModeDual(HidControllerID id) {
return _hidCmdWithInputU32(124, id); return _hidCmdWithInputU32(124, hidControllerIDToOfficial(id));
} }
Result hidMergeSingleJoyAsDualJoy(HidControllerID id0, HidControllerID id1) { Result hidMergeSingleJoyAsDualJoy(HidControllerID id0, HidControllerID id1) {
@ -1063,8 +1063,8 @@ Result hidMergeSingleJoyAsDualJoy(HidControllerID id0, HidControllerID id1) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 125; raw->cmd_id = 125;
raw->id0 = id0; raw->id0 = hidControllerIDToOfficial(id0);
raw->id1 = id1; raw->id1 = hidControllerIDToOfficial(id1);
raw->AppletResourceUserId = AppletResourceUserId; raw->AppletResourceUserId = AppletResourceUserId;
rc = serviceIpcDispatch(&g_hidSrv); rc = serviceIpcDispatch(&g_hidSrv);
@ -1739,3 +1739,44 @@ Result hidResetSevenSixAxisSensorTimestamp(void) {
return _hidCmdWithNoInput(310); return _hidCmdWithNoInput(310);
} }
Result hidGetNpadInterfaceType(HidControllerID id, u8 *out) {
if (hosversionBefore(4,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc;
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 405;
raw->id = hidControllerIDToOfficial(id);
rc = serviceIpcDispatch(&g_hidSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u8 out;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) *out = resp->out;
}
return rc;
}

View File

@ -11,11 +11,35 @@
static Service g_hiddbgSrv; static Service g_hiddbgSrv;
static u64 g_hiddbgRefCnt; static u64 g_hiddbgRefCnt;
static size_t g_hiddbgPtrbufsize;
static bool g_hiddbgHdlsInitialized; static bool g_hiddbgHdlsInitialized;
static TransferMemory g_hiddbgHdlsTmem; static TransferMemory g_hiddbgHdlsTmem;
static const u32 g_hiddbgDeviceTypeInternalTable[] = {
BIT(20), // DeviceType 0 Invalid
BIT(0*4+2), // DeviceType 1 JoyRight
BIT(0*4+1), // DeviceType 2 JoyLeft
BIT(1*4+0), // DeviceType 3 FullKey
BIT(1*4+1), // DeviceType 4 JoyLeft
BIT(1*4+2), // DeviceType 5 JoyRight
BIT(8), // DeviceType 6 FullKey
BIT(11), // DeviceType 7 LarkLeft (HVC)
BIT(12), // DeviceType 8 LarkRight (HVC)
BIT(13), // DeviceType 9 LarkLeft (NES)
BIT(14), // DeviceType 10 LarkRight (NES)
BIT(15), // DeviceType 11 Invalid
BIT(16), // DeviceType 12 Palma (Invalid for DeviceTypeInternal)
BIT(9), // DeviceType 13 FullKey
BIT(20), // DeviceType 14 Invalid
BIT(10), // DeviceType 15 FullKey
BIT(18), // DeviceType 16 Invalid
BIT(19), // DeviceType 17 Invalid
BIT(20), // DeviceType 18 Invalid
BIT(21), // DeviceType 19 ::HidDeviceTypeBits_System with HidControllerType |= TYPE_PROCONTROLLER.
BIT(22), // DeviceType 20 ::HidDeviceTypeBits_System with HidControllerType |= TYPE_JOYCON_PAIR.
BIT(23), // DeviceType 21 ::HidDeviceType System with HidControllerType |= TYPE_JOYCON_PAIR.
};
Result hiddbgInitialize(void) { Result hiddbgInitialize(void) {
atomicIncrement64(&g_hiddbgRefCnt); atomicIncrement64(&g_hiddbgRefCnt);
@ -24,8 +48,6 @@ Result hiddbgInitialize(void) {
Result rc = smGetService(&g_hiddbgSrv, "hid:dbg"); Result rc = smGetService(&g_hiddbgSrv, "hid:dbg");
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_hiddbgSrv.handle, &g_hiddbgPtrbufsize);
if (R_FAILED(rc)) hiddbgExit(); if (R_FAILED(rc)) hiddbgExit();
return rc; return rc;
@ -292,8 +314,55 @@ Result hiddbgReadSerialFlash(u32 offset, void* buffer, size_t size, u64 UniquePa
return rc; return rc;
} }
Result hiddbgGetUniquePadDeviceTypeSetInternal(u64 UniquePadId, u32 *out) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc;
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 UniquePadId;
} *raw;
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 234;
raw->UniquePadId = UniquePadId;
rc = serviceIpcDispatch(&g_hiddbgSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 out;
} *resp;
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) { //Pre-9.0.0 output is an u32, with [9.0.0+] it's an u8.
if (hosversionBefore(9,0,0))
*out = resp->out;
else
*out = resp->out & 0xFF;
}
}
return rc;
}
Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *total_entries) { Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *total_entries) {
if (hosversionBefore(5,0,0)) if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc; Result rc;
@ -326,6 +395,8 @@ Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
resp = r.Raw; resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries; if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
} }
@ -333,7 +404,7 @@ Result hiddbgGetAbstractedPadHandles(u64 *AbstractedPadHandles, s32 count, s32 *
} }
Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadState *state) { Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadState *state) {
if (hosversionBefore(5,0,0)) if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc; Result rc;
@ -366,6 +437,8 @@ Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadS
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
resp = r.Raw; resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && state) memcpy(state, &resp->state, sizeof(*state)); if (R_SUCCEEDED(rc) && state) memcpy(state, &resp->state, sizeof(*state));
} }
@ -373,7 +446,7 @@ Result hiddbgGetAbstractedPadState(u64 AbstractedPadHandle, HiddbgAbstractedPadS
} }
Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedPadState *states, s32 count, s32 *total_entries) { Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedPadState *states, s32 count, s32 *total_entries) {
if (hosversionBefore(5,0,0)) if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc; Result rc;
@ -387,7 +460,7 @@ Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedP
} *raw; } *raw;
ipcAddRecvStatic(&c, AbstractedPadHandles, sizeof(u64)*count, 0); ipcAddRecvStatic(&c, AbstractedPadHandles, sizeof(u64)*count, 0);
ipcAddRecvSmart(&c, g_hiddbgPtrbufsize, states, sizeof(HiddbgAbstractedPadState)*count, 0); ipcAddRecvSmart(&c, g_hiddbgSrv.pointer_buffer_size, states, sizeof(HiddbgAbstractedPadState)*count, 0);
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
@ -407,6 +480,8 @@ Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedP
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
resp = r.Raw; resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries; if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
} }
@ -414,7 +489,7 @@ Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedP
} }
Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const HiddbgAbstractedPadState *state) { Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const HiddbgAbstractedPadState *state) {
if (hosversionBefore(5,0,0)) if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc; Result rc;
@ -448,13 +523,15 @@ Result hiddbgSetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId, const Hiddbg
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
resp = r.Raw; resp = r.Raw;
rc = resp->result;
} }
return rc; return rc;
} }
Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId) { Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId) {
if (hosversionBefore(5,0,0)) if (hosversionBefore(5,0,0) || hosversionAtLeast(9,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc; Result rc;
@ -485,6 +562,8 @@ Result hiddbgUnsetAutoPilotVirtualPadState(s8 AbstractedVirtualPadId) {
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp)); serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
resp = r.Raw; resp = r.Raw;
rc = resp->result;
} }
return rc; return rc;
@ -497,6 +576,84 @@ Result hiddbgUnsetAllAutoPilotVirtualPadState(void) {
return _hiddbgCmdNoIO(323); return _hiddbgCmdNoIO(323);
} }
static u32 _hiddbgConvertDeviceTypeToDeviceTypeInternal(u8 deviceType) {
if (deviceType >= sizeof(g_hiddbgDeviceTypeInternalTable)/sizeof(u32)) return g_hiddbgDeviceTypeInternalTable[0];
return g_hiddbgDeviceTypeInternalTable[deviceType];
}
static u8 _hiddbgConvertDeviceTypeInternalToDeviceType(u32 deviceType) {
for (u32 i=0; i<sizeof(g_hiddbgDeviceTypeInternalTable)/sizeof(u32); i++) {
if (deviceType == g_hiddbgDeviceTypeInternalTable[i]) return i;
}
return 0;
}
static void _hiddbgConvertHdlsDeviceInfoToV7(HiddbgHdlsDeviceInfoV7 *out, const HiddbgHdlsDeviceInfo *in) {
memset(out, 0, sizeof(*out));
out->deviceTypeInternal = _hiddbgConvertDeviceTypeToDeviceTypeInternal(in->deviceType);
out->singleColorBody = in->singleColorBody;
out->singleColorButtons = in->singleColorButtons;
out->npadInterfaceType = in->npadInterfaceType;
}
static void _hiddbgConvertHdlsDeviceInfoFromV7(HiddbgHdlsDeviceInfo *out, const HiddbgHdlsDeviceInfoV7 *in) {
memset(out, 0, sizeof(*out));
out->deviceType = _hiddbgConvertDeviceTypeInternalToDeviceType(in->deviceTypeInternal);
out->npadInterfaceType = in->npadInterfaceType;
out->singleColorBody = in->singleColorBody;
out->singleColorButtons = in->singleColorButtons;
//Leave out color*Grip at zero since V7 doesn't have those.
}
static void _hiddbgConverHiddbgHdlsStateToV7(HiddbgHdlsStateV7 *out, const HiddbgHdlsState *in) {
memset(out, 0, sizeof(*out));
out->powerConnected = (in->flags & BIT(0)) != 0;
out->flags = (in->flags & BIT(1)) != 0;
out->batteryCharge = in->batteryCharge;
out->buttons = in->buttons;
memcpy(out->joysticks, in->joysticks, sizeof(in->joysticks));
out->unk_x20 = in->unk_x20;
}
static void _hiddbgConverHiddbgHdlsStateFromV7(HiddbgHdlsState *out, const HiddbgHdlsStateV7 *in) {
memset(out, 0, sizeof(*out));
out->batteryCharge = in->batteryCharge;
out->flags = (in->powerConnected & 1) | ((in->flags & 1)<<1);
out->buttons = in->buttons;
memcpy(out->joysticks, in->joysticks, sizeof(in->joysticks));
out->unk_x20 = in->unk_x20;
}
static void _hiddbgConvertHdlsStateListToV7(HiddbgHdlsStateListV7 *out, const HiddbgHdlsStateList *in) {
s32 count;
memset(out, 0, sizeof(*out));
out->total_entries = in->total_entries;
count = out->total_entries > 0x10 ? 0x10 : out->total_entries;
for (s32 i=0; i<count; i++) {
out->entries[i].HdlsHandle = in->entries[i].HdlsHandle;
_hiddbgConvertHdlsDeviceInfoToV7(&out->entries[i].device, &in->entries[i].device);
_hiddbgConverHiddbgHdlsStateToV7(&out->entries[i].state, &in->entries[i].state);
}
}
static void _hiddbgConvertHdlsStateListFromV7(HiddbgHdlsStateList *out, const HiddbgHdlsStateListV7 *in) {
s32 count;
memset(out, 0, sizeof(*out));
out->total_entries = in->total_entries;
count = out->total_entries > 0x10 ? 0x10 : out->total_entries;
for (s32 i=0; i<count; i++) {
out->entries[i].HdlsHandle = in->entries[i].HdlsHandle;
_hiddbgConvertHdlsDeviceInfoFromV7(&out->entries[i].device, &in->entries[i].device);
_hiddbgConverHiddbgHdlsStateFromV7(&out->entries[i].state, &in->entries[i].state);
}
}
static Result _hiddbgAttachHdlsWorkBuffer(TransferMemory *tmem) { static Result _hiddbgAttachHdlsWorkBuffer(TransferMemory *tmem) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
@ -594,7 +751,15 @@ Result hiddbgDumpHdlsStates(HiddbgHdlsStateList *state) {
rc = _hiddbgCmdNoIO(327); rc = _hiddbgCmdNoIO(327);
if (R_FAILED(rc)) return rc; if (R_FAILED(rc)) return rc;
if (state) memcpy(state, g_hiddbgHdlsTmem.src_addr, sizeof(*state)); if (state) {
if (hosversionBefore(9,0,0)) {
HiddbgHdlsStateListV7 statev7;
memcpy(&statev7, g_hiddbgHdlsTmem.src_addr, sizeof(statev7));
_hiddbgConvertHdlsStateListFromV7(state, &statev7);
}
else
memcpy(state, g_hiddbgHdlsTmem.src_addr, sizeof(*state));
}
return rc; return rc;
} }
@ -622,10 +787,54 @@ Result hiddbgApplyHdlsStateList(const HiddbgHdlsStateList *state) {
if (state==NULL) if (state==NULL)
return MAKERESULT(Module_Libnx, LibnxError_BadInput); return MAKERESULT(Module_Libnx, LibnxError_BadInput);
memcpy(g_hiddbgHdlsTmem.src_addr, state, sizeof(*state)); if (hosversionBefore(9,0,0)) {
HiddbgHdlsStateListV7 statev7;
_hiddbgConvertHdlsStateListToV7(&statev7, state);
memcpy(g_hiddbgHdlsTmem.src_addr, &statev7, sizeof(statev7));
}
else
memcpy(g_hiddbgHdlsTmem.src_addr, state, sizeof(*state));
return _hiddbgCmdNoIO(329); return _hiddbgCmdNoIO(329);
} }
static Result _hiddbgAttachHdlsVirtualDeviceV7(u64 *HdlsHandle, const HiddbgHdlsDeviceInfoV7 *info) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
HiddbgHdlsDeviceInfoV7 info;
} *raw;
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 330;
raw->info = *info;
Result rc = serviceIpcDispatch(&g_hiddbgSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 handle;
} *resp;
serviceIpcParse(&g_hiddbgSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && HdlsHandle) *HdlsHandle = resp->handle;
}
return rc;
}
static Result _hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo *info) { static Result _hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo *info) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
@ -670,7 +879,13 @@ Result hiddbgAttachHdlsVirtualDevice(u64 *HdlsHandle, const HiddbgHdlsDeviceInfo
if (!g_hiddbgHdlsInitialized) if (!g_hiddbgHdlsInitialized)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
return _hiddbgAttachHdlsVirtualDevice(HdlsHandle, info); if (hosversionBefore(9,0,0)) {
HiddbgHdlsDeviceInfoV7 infov7;
_hiddbgConvertHdlsDeviceInfoToV7(&infov7, info);
return _hiddbgAttachHdlsVirtualDeviceV7(HdlsHandle, &infov7);
}
else
return _hiddbgAttachHdlsVirtualDevice(HdlsHandle, info);
} }
Result hiddbgDetachHdlsVirtualDevice(u64 HdlsHandle) { Result hiddbgDetachHdlsVirtualDevice(u64 HdlsHandle) {
@ -690,16 +905,30 @@ static Result _hiddbgSetHdlsState(u64 HdlsHandle, const HiddbgHdlsState *state)
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
HiddbgHdlsState state; union {
u64 handle; struct {
HiddbgHdlsStateV7 state;
u64 handle;
} v7; // [7.0.0-8.1.0]
struct {
u64 handle;
HiddbgHdlsState state;
} v9; // [9.0.0+]
};
} *raw; } *raw;
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw)); raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 332; raw->cmd_id = 332;
memcpy(&raw->state, state, sizeof(*state)); if (hosversionBefore(9,0,0)) {
raw->handle = HdlsHandle; _hiddbgConverHiddbgHdlsStateToV7(&raw->v7.state, state);
raw->v7.handle = HdlsHandle;
}
else {
raw->v9.handle = HdlsHandle;
memcpy(&raw->v9.state, state, sizeof(*state));
}
Result rc = serviceIpcDispatch(&g_hiddbgSrv); Result rc = serviceIpcDispatch(&g_hiddbgSrv);

View File

@ -6,20 +6,17 @@
#include "services/sm.h" #include "services/sm.h"
static Service g_i2cSrv; static Service g_i2cSrv;
static size_t g_i2cSrvPtrBufSize;
static u64 g_refCnt; static u64 g_refCnt;
Result i2cInitialize(void) { Result i2cInitialize(void) {
Result rc = 0; Result rc = 0;
atomicIncrement64(&g_refCnt); atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_i2cSrv)) if (serviceIsActive(&g_i2cSrv))
return 0; return 0;
rc = smGetService(&g_i2cSrv, "i2c"); rc = smGetService(&g_i2cSrv, "i2c");
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_i2cSrv.handle, &g_i2cSrvPtrBufSize);
if (R_FAILED(rc)) i2cExit(); if (R_FAILED(rc)) i2cExit();
@ -28,7 +25,6 @@ Result i2cInitialize(void) {
void i2cExit(void) { void i2cExit(void) {
if (atomicDecrement64(&g_refCnt) == 0) { if (atomicDecrement64(&g_refCnt) == 0) {
g_i2cSrvPtrBufSize = 0;
serviceClose(&g_i2cSrv); serviceClose(&g_i2cSrv);
} }
} }
@ -78,7 +74,7 @@ Result i2cOpenSession(I2cSession *out, I2cDevice dev) {
Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransactionOption option) { Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransactionOption option) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendSmart(&c, g_i2cSrvPtrBufSize, buf, size, 0); ipcAddSendSmart(&c, s->s.pointer_buffer_size, buf, size, 0);
struct { struct {
u64 magic; u64 magic;
@ -113,7 +109,7 @@ Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransa
Result i2csessionReceiveAuto(I2cSession *s, void *buf, size_t size, I2cTransactionOption option) { Result i2csessionReceiveAuto(I2cSession *s, void *buf, size_t size, I2cTransactionOption option) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddRecvSmart(&c, g_i2cSrvPtrBufSize, buf, size, 0); ipcAddRecvSmart(&c, s->s.pointer_buffer_size, buf, size, 0);
struct { struct {
u64 magic; u64 magic;
@ -149,7 +145,7 @@ Result i2csessionExecuteCommandList(I2cSession *s, void *dst, size_t dst_size, c
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendStatic(&c, cmd_list, cmd_list_size, 0); ipcAddSendStatic(&c, cmd_list, cmd_list_size, 0);
ipcAddRecvSmart(&c, g_i2cSrvPtrBufSize, dst, dst_size, 0); ipcAddRecvSmart(&c, s->s.pointer_buffer_size, dst, dst_size, 0);
struct { struct {
u64 magic; u64 magic;

View File

@ -7,17 +7,18 @@
#include "services/lr.h" #include "services/lr.h"
#include "services/fs.h" #include "services/fs.h"
#include "services/sm.h" #include "services/sm.h"
#include "runtime/hosversion.h"
static Service g_managerSrv; static Service g_managerSrv;
static u64 g_managerRefCnt; static u64 g_managerRefCnt;
Result lrInitialize(void) { Result lrInitialize(void) {
atomicIncrement64(&g_managerRefCnt); atomicIncrement64(&g_managerRefCnt);
if (serviceIsActive(&g_managerSrv)) { if (serviceIsActive(&g_managerSrv)) {
return 0; return 0;
} }
return smGetService(&g_managerSrv, "lr"); return smGetService(&g_managerSrv, "lr");
} }
@ -34,19 +35,19 @@ Service* lrGetServiceSession(void) {
Result lrOpenLocationResolver(FsStorageId storage, LrLocationResolver* out) { Result lrOpenLocationResolver(FsStorageId storage, LrLocationResolver* out) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
u32 storage_id; // Actually u8 u32 storage_id; // Actually u8
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 0; raw->cmd_id = 0;
raw->storage_id = (u32)storage; raw->storage_id = (u32)storage;
Result rc = serviceIpcDispatch(&g_managerSrv); Result rc = serviceIpcDispatch(&g_managerSrv);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -63,24 +64,24 @@ Result lrOpenLocationResolver(FsStorageId storage, LrLocationResolver* out) {
serviceCreate(&out->s, r.Handles[0]); serviceCreate(&out->s, r.Handles[0]);
} }
} }
return rc; return rc;
} }
Result lrOpenRegisteredLocationResolver(LrRegisteredLocationResolver* out) { Result lrOpenRegisteredLocationResolver(LrRegisteredLocationResolver* out) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 1; raw->cmd_id = 1;
Result rc = serviceIpcDispatch(&g_managerSrv); Result rc = serviceIpcDispatch(&g_managerSrv);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -97,11 +98,11 @@ Result lrOpenRegisteredLocationResolver(LrRegisteredLocationResolver* out) {
serviceCreate(&out->s, r.Handles[0]); serviceCreate(&out->s, r.Handles[0]);
} }
} }
return rc; return rc;
} }
/* /*
All the LocationResolver/RegisteredLocationResolver "Resolve" commands have a common API. All the LocationResolver/RegisteredLocationResolver "Resolve" commands have a common API.
This is a helper function to perform the work for those funcs, given a command ID. This is a helper function to perform the work for those funcs, given a command ID.
*/ */
@ -110,18 +111,18 @@ static Result _lrResolvePath(Service* s, u64 cmd_id, u64 tid, char *out) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddRecvStatic(&c, out_path, FS_MAX_PATH, 0); ipcAddRecvStatic(&c, out_path, FS_MAX_PATH, 0);
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
u64 tid; u64 tid;
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id; raw->cmd_id = cmd_id;
raw->tid = tid; raw->tid = tid;
Result rc = serviceIpcDispatch(s); Result rc = serviceIpcDispatch(s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
@ -139,11 +140,11 @@ static Result _lrResolvePath(Service* s, u64 cmd_id, u64 tid, char *out) {
strncpy(out, out_path, FS_MAX_PATH); strncpy(out, out_path, FS_MAX_PATH);
} }
} }
return rc; return rc;
} }
/* /*
All the LocationResolver/RegisteredLocationResolver "Redirect" commands have a common API. All the LocationResolver/RegisteredLocationResolver "Redirect" commands have a common API.
This is a helper function to perform the work for those funcs, given a command ID. This is a helper function to perform the work for those funcs, given a command ID.
*/ */
@ -152,18 +153,18 @@ static Result _lrRedirectPath(Service* s, u64 cmd_id, u64 tid, const char *path)
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0); ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0);
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
u64 tid; u64 tid;
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id; raw->cmd_id = cmd_id;
raw->tid = tid; raw->tid = tid;
strncpy(send_path, path, FS_MAX_PATH); strncpy(send_path, path, FS_MAX_PATH);
Result rc = serviceIpcDispatch(s); Result rc = serviceIpcDispatch(s);
@ -178,10 +179,55 @@ static Result _lrRedirectPath(Service* s, u64 cmd_id, u64 tid, const char *path)
rc = resp->result; rc = resp->result;
} }
return rc; return rc;
} }
/*
In 9.0.0, "RedirectApplication" commands began taking in a second tid argument.
This is a helper function to perform the work for those funcs, given a command ID.
*/
static Result _lrRedirectApplicationPath(Service* s, u64 cmd_id, u64 tid, u64 tid2, const char *path) {
// On < 9.0.0, call the original redirection helper.
if (hosversionBefore(9,0,0)) {
return _lrRedirectPath(s, cmd_id, tid, path);
}
char send_path[FS_MAX_PATH+1] = {0};
IpcCommand c;
ipcInitialize(&c);
ipcAddSendStatic(&c, send_path, FS_MAX_PATH, 0);
struct {
u64 magic;
u64 cmd_id;
u64 tid;
u64 tid2;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->tid = tid;
raw->tid2 = tid2;
strncpy(send_path, path, FS_MAX_PATH);
Result rc = serviceIpcDispatch(s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result lrLrResolveProgramPath(LrLocationResolver* lr, u64 tid, char *out) { Result lrLrResolveProgramPath(LrLocationResolver* lr, u64 tid, char *out) {
return _lrResolvePath(&lr->s, 0, tid, out); return _lrResolvePath(&lr->s, 0, tid, out);
@ -203,36 +249,36 @@ Result lrLrResolveDataPath(LrLocationResolver* lr, u64 tid, char *out) {
return _lrResolvePath(&lr->s, 4, tid, out); return _lrResolvePath(&lr->s, 4, tid, out);
} }
Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, const char *path) { Result lrLrRedirectApplicationControlPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path) {
return _lrRedirectPath(&lr->s, 5, tid, path); return _lrRedirectApplicationPath(&lr->s, 5, tid, tid2, path);
} }
Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, const char *path) { Result lrLrRedirectApplicationHtmlDocumentPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path) {
return _lrRedirectPath(&lr->s, 6, tid, path); return _lrRedirectApplicationPath(&lr->s, 6, tid, tid2, path);
} }
Result lrLrResolveLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out) { Result lrLrResolveApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, char *out) {
return _lrResolvePath(&lr->s, 7, tid, out); return _lrResolvePath(&lr->s, 7, tid, out);
} }
Result lrLrRedirectLegalInformationPath(LrLocationResolver* lr, u64 tid, const char *path) { Result lrLrRedirectApplicationLegalInformationPath(LrLocationResolver* lr, u64 tid, u64 tid2, const char *path) {
return _lrRedirectPath(&lr->s, 8, tid, path); return _lrRedirectApplicationPath(&lr->s, 8, tid, tid2, path);
} }
Result lrLrRefresh(LrLocationResolver* lr) { Result lrLrRefresh(LrLocationResolver* lr) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
} *raw; } *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw)); raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 9; raw->cmd_id = 9;
Result rc = serviceIpcDispatch(&lr->s); Result rc = serviceIpcDispatch(&lr->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -245,7 +291,7 @@ Result lrLrRefresh(LrLocationResolver* lr) {
rc = resp->result; rc = resp->result;
} }
return rc; return rc;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,22 @@
/** #include "service_guard.h"
* @file nifm.c
* @brief Network interface service IPC wrapper.
* @author shadowninja108, shibboleet
* @copyright libnx Authors
*/
#include "services/nifm.h" #include "services/nifm.h"
#include "arm/atomics.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
static NifmServiceType g_nifmServiceType = NifmServiceType_NotInitialized; static NifmServiceType g_nifmServiceType = NifmServiceType_NotInitialized;
static Service g_nifmSrv; static Service g_nifmSrv;
static Service g_nifmIGS; static Service g_nifmIGS;
static u64 g_refCnt;
static Result _nifmCreateGeneralService(Service* out, u64 in); static Result _nifmCreateGeneralService(Service* srv_out);
static Result _nifmCreateGeneralServiceOld(Service* out); static Result _nifmCreateGeneralServiceOld(Service* srv_out);
NX_GENERATE_SERVICE_GUARD(nifm);
void nifmSetServiceType(NifmServiceType serviceType) { void nifmSetServiceType(NifmServiceType serviceType) {
g_nifmServiceType = serviceType; g_nifmServiceType = serviceType;
} }
Result nifmInitialize(void) { Result _nifmInitialize(void) {
atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_nifmSrv))
return 0;
Result rc = 0; Result rc = 0;
switch (g_nifmServiceType) { switch (g_nifmServiceType) {
case NifmServiceType_NotInitialized: case NifmServiceType_NotInitialized:
@ -47,393 +36,125 @@ Result nifmInitialize(void) {
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
if (hosversionAtLeast(3,0,0)) if (hosversionAtLeast(3,0,0))
rc = _nifmCreateGeneralService(&g_nifmIGS, 0); // What does this parameter do? rc = _nifmCreateGeneralService(&g_nifmIGS);
else else
rc = _nifmCreateGeneralServiceOld(&g_nifmIGS); rc = _nifmCreateGeneralServiceOld(&g_nifmIGS);
} }
if (R_FAILED(rc))
nifmExit();
return rc; return rc;
} }
void nifmExit(void) { void _nifmCleanup(void) {
if (atomicDecrement64(&g_refCnt) == 0) { serviceClose(&g_nifmIGS);
serviceClose(&g_nifmIGS); serviceClose(&g_nifmSrv);
serviceClose(&g_nifmSrv); g_nifmServiceType = NifmServiceType_NotInitialized;
g_nifmServiceType = NifmServiceType_NotInitialized; }
}
Service* nifmGetServiceSession_StaticService(void) {
return &g_nifmSrv;
}
Service* nifmGetServiceSession_GeneralService(void) {
return &g_nifmIGS;
}
static Result _nifmCmdNoIO(Service* srv, u32 cmd_id) {
serviceAssumeDomain(srv);
return serviceDispatch(srv, cmd_id);
}
static Result _nifmCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
serviceAssumeDomain(srv);
return serviceDispatch(srv, cmd_id,
.out_num_objects = 1,
.out_objects = srv_out,
);
}
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);
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _nifmCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) {
u8 tmp=0;
Result rc = _nifmCmdNoInOutU8(srv, &tmp, cmd_id);
if (R_SUCCEEDED(rc) && out) *out = tmp!=0;
return rc;
}
static Result _nifmCmdInU8NoOut(Service* srv, u8 inval, u64 cmd_id) {
serviceAssumeDomain(srv);
return serviceDispatchIn(srv, cmd_id, inval);
}
static Result _nifmCmdInBoolNoOut(Service* srv, bool inval, u32 cmd_id) {
return _nifmCmdInU8NoOut(srv, inval!=0, cmd_id);
}
static Result _nifmCreateGeneralServiceOld(Service* srv_out) {
return _nifmCmdGetSession(&g_nifmSrv, srv_out, 4);
}
static Result _nifmCreateGeneralService(Service* srv_out) {
u64 reserved=0;
serviceAssumeDomain(&g_nifmSrv);
return serviceDispatchIn(&g_nifmSrv, 5, reserved,
.in_send_pid = true,
.out_num_objects = 1,
.out_objects = srv_out,
);
} }
Result nifmGetCurrentIpAddress(u32* out) { Result nifmGetCurrentIpAddress(u32* out) {
IpcCommand c; return _nifmCmdNoInOutU32(&g_nifmIGS, out, 12);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 12;
Result rc = serviceIpcDispatch(&g_nifmIGS);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 out;
} *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
*out = resp->out;
}
return rc;
}
Result nifmIsWirelessCommunicationEnabled(bool* out) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 17;
Result rc = serviceIpcDispatch(&g_nifmIGS);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u8 out;
} *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out)
*out = resp->out != 0;
}
return rc;
} }
Result nifmSetWirelessCommunicationEnabled(bool enable) { Result nifmSetWirelessCommunicationEnabled(bool enable) {
if (g_nifmServiceType < NifmServiceType_System) if (g_nifmServiceType < NifmServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
IpcCommand c; return _nifmCmdInBoolNoOut(&g_nifmIGS, enable, 16);
ipcInitialize(&c); }
Result nifmIsWirelessCommunicationEnabled(bool* out) {
return _nifmCmdNoInOutBool(&g_nifmIGS, out, 17);
}
Result nifmGetInternetConnectionStatus(NifmInternetConnectionType* connectionType, u32* wifiStrength, NifmInternetConnectionStatus* connectionStatus) {
struct { struct {
u64 magic; u8 out1;
u64 cmd_id; u8 out2;
u8 value; u8 out3;
} *raw; } out;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 16;
raw->value = enable!= 0;
Result rc = serviceIpcDispatch(&g_nifmIGS);
serviceAssumeDomain(&g_nifmIGS);
Result rc = serviceDispatchOut(&g_nifmIGS, 18, out);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; if (connectionType) *connectionType = out.out1;
struct { if (wifiStrength) *wifiStrength = out.out2;
u64 magic; if (connectionStatus) *connectionStatus = out.out3;
u64 result;
} *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
} }
return rc; return rc;
} }
Result nifmIsEthernetCommunicationEnabled(bool* out) { Result nifmIsEthernetCommunicationEnabled(bool* out) {
IpcCommand c; return _nifmCmdNoInOutBool(&g_nifmIGS, out, 20);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 20;
Result rc = serviceIpcDispatch(&g_nifmIGS);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u8 out;
} *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out)
*out = resp->out != 0;
}
return rc;
} }
Result nifmIsAnyForegroundRequestAccepted(bool* out) { Result nifmIsAnyForegroundRequestAccepted(bool* out) {
IpcCommand c; return _nifmCmdNoInOutBool(&g_nifmIGS, out, 22);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 22;
Result rc = serviceIpcDispatch(&g_nifmIGS);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u8 out;
} *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out)
*out = resp->out != 0;
}
return rc;
} }
Result nifmPutToSleep(void) { Result nifmPutToSleep(void) {
IpcCommand c; return _nifmCmdNoIO(&g_nifmIGS, 23);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 23;
Result rc = serviceIpcDispatch(&g_nifmIGS);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result nifmWakeUp(void) { Result nifmWakeUp(void) {
IpcCommand c; return _nifmCmdNoIO(&g_nifmIGS, 24);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 24;
Result rc = serviceIpcDispatch(&g_nifmIGS);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result nifmGetInternetConnectionStatus(NifmInternetConnectionType* connectionType, u32* wifiStrength, NifmInternetConnectionStatus* connectionStatus)
{
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_nifmIGS, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 18;
Result rc = serviceIpcDispatch(&g_nifmIGS);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u8 out1;
u8 out2;
u8 out3;
} PACKED *resp;
serviceIpcParse(&g_nifmIGS, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (connectionType)
*connectionType = resp->out1;
if (wifiStrength)
*wifiStrength = resp->out2;
if (connectionStatus)
*connectionStatus = resp->out3;
}
}
return rc;
}
static Result _nifmCreateGeneralService(Service* out, u64 in) {
IpcCommand c;
ipcInitialize(&c);
ipcSendPid(&c);
struct {
u64 magic;
u64 cmd_id;
u64 param;
} PACKED *raw;
raw = serviceIpcPrepareHeader(&g_nifmSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
raw->param = in;
Result rc = serviceIpcDispatch(&g_nifmSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_nifmSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
serviceCreateSubservice(out, &g_nifmSrv, &r, 0);
}
return rc;
}
static Result _nifmCreateGeneralServiceOld(Service* out) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} PACKED *raw;
raw = serviceIpcPrepareHeader(&g_nifmSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 4;
Result rc = serviceIpcDispatch(&g_nifmSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_nifmSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
serviceCreateSubservice(out, &g_nifmSrv, &r, 0);
}
return rc;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,26 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h> #include <string.h>
#include "types.h" #include "service_guard.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "kernel/tmem.h" #include "kernel/tmem.h"
#include "services/applet.h" #include "services/applet.h"
#include "nvidia/ioctl.h"
#include "services/nv.h" #include "services/nv.h"
#include "services/sm.h" #include "nvidia/ioctl.h"
__attribute__((weak)) u32 __nx_nv_transfermem_size = 0x800000; __attribute__((weak)) u32 __nx_nv_transfermem_size = 0x800000;
static Service g_nvSrv; static Service g_nvSrv;
static Service g_nvSrvClone; static Service g_nvSrvClone;
static u64 g_refCnt;
static size_t g_nvIpcBufferSize = 0; static size_t g_nvIpcBufferSize = 0;
static TransferMemory g_nvTransfermem; static TransferMemory g_nvTransfermem;
static Result _nvInitialize(Handle proc, Handle sharedmem, u32 transfermem_size); static Result _nvCmdInitialize(Handle proc, Handle sharedmem, u32 transfermem_size);
static Result _nvSetClientPID(u64 AppletResourceUserId); static Result _nvSetClientPID(u64 AppletResourceUserId);
Result nvInitialize(void) NX_GENERATE_SERVICE_GUARD(nv);
Result _nvInitialize(void)
{ {
atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_nvSrv))
return 0;
Result rc = 0; Result rc = 0;
u64 AppletResourceUserId = 0; u64 AppletResourceUserId = 0;
@ -51,22 +44,17 @@ Result nvInitialize(void)
} }
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
g_nvIpcBufferSize = 0; g_nvIpcBufferSize = g_nvSrv.pointer_buffer_size;
rc = ipcQueryPointerBufferSize(g_nvSrv.handle, &g_nvIpcBufferSize);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = tmemCreate(&g_nvTransfermem, __nx_nv_transfermem_size, Perm_None); rc = tmemCreate(&g_nvTransfermem, __nx_nv_transfermem_size, Perm_None);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = _nvInitialize(CUR_PROCESS_HANDLE, g_nvTransfermem.handle, __nx_nv_transfermem_size); rc = _nvCmdInitialize(CUR_PROCESS_HANDLE, g_nvTransfermem.handle, __nx_nv_transfermem_size);
// Clone the session handle - the cloned session is used to execute certain commands in parallel // Clone the session handle - the cloned session is used to execute certain commands in parallel
Handle nv_clone = INVALID_HANDLE;
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = ipcCloneSession(g_nvSrv.handle, 1, &nv_clone); rc = serviceCloneEx(&g_nvSrv, 1, &g_nvSrvClone);
if (R_SUCCEEDED(rc))
serviceCreate(&g_nvSrvClone, nv_clone);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
{ {
@ -84,120 +72,43 @@ Result nvInitialize(void)
return rc; return rc;
} }
void nvExit(void) void _nvCleanup(void)
{ {
if (atomicDecrement64(&g_refCnt) == 0) { serviceClose(&g_nvSrvClone);
serviceClose(&g_nvSrvClone); serviceClose(&g_nvSrv);
serviceClose(&g_nvSrv); tmemClose(&g_nvTransfermem);
tmemClose(&g_nvTransfermem);
}
} }
static Result _nvInitialize(Handle proc, Handle sharedmem, u32 transfermem_size) { static Result _nvCmdInitialize(Handle proc, Handle sharedmem, u32 transfermem_size)
IpcCommand c; {
ipcInitialize(&c); return serviceDispatchIn(&g_nvSrv, 3, transfermem_size,
.in_num_handles = 2,
struct { .in_handles = { proc, sharedmem },
u64 magic; );
u64 cmd_id;
u32 transfermem_size;
} *raw;
ipcSendHandleCopy(&c, proc);
ipcSendHandleCopy(&c, sharedmem);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 3;
raw->transfermem_size = transfermem_size;
Result rc = serviceIpcDispatch(&g_nvSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
static Result _nvSetClientPID(u64 AppletResourceUserId) { static Result _nvSetClientPID(u64 AppletResourceUserId)
IpcCommand c; {
ipcInitialize(&c); return serviceDispatchIn(&g_nvSrv, 8, AppletResourceUserId, .in_send_pid = true);
struct {
u64 magic;
u64 cmd_id;
u64 AppletResourceUserId;
} *raw;
ipcSendPid(&c);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 8;
raw->AppletResourceUserId = AppletResourceUserId;
Result rc = serviceIpcDispatch(&g_nvSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result nvOpen(u32 *fd, const char *devicepath) { Result nvOpen(u32 *fd, const char *devicepath)
IpcCommand c; {
ipcInitialize(&c);
struct { struct {
u64 magic; u32 fd;
u64 cmd_id; u32 error;
} *raw; } out;
ipcAddSendBuffer(&c, devicepath, strlen(devicepath), 0); Result rc = serviceDispatchOut(&g_nvSrv, 0, out,
.buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },
.buffers = { { devicepath, strlen(devicepath) } },
);
raw = ipcPrepareHeader(&c, sizeof(*raw)); if (R_SUCCEEDED(rc))
raw->magic = SFCI_MAGIC; rc = nvConvertError(out.error);
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&g_nvSrv); if (R_SUCCEEDED(rc) && fd)
*fd = out.fd;
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 fd;
u32 error;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
rc = nvConvertError(resp->error);
if (R_SUCCEEDED(rc))
*fd = resp->fd;
}
return rc; return rc;
} }
@ -215,194 +126,120 @@ static inline Service* _nvGetSessionForRequest(u32 request)
return &g_nvSrv; return &g_nvSrv;
} }
Result nvIoctl(u32 fd, u32 request, void* argp) { Result nvIoctl(u32 fd, u32 request, void* argp)
IpcCommand c; {
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 fd;
u32 request;
} *raw;
size_t bufsize = _NV_IOC_SIZE(request); size_t bufsize = _NV_IOC_SIZE(request);
u32 dir = _NV_IOC_DIR(request); u32 dir = _NV_IOC_DIR(request);
void* buf_send = NULL, *buf_recv = NULL; void *buf_send = NULL, *buf_recv = NULL;
size_t buf_send_size = 0, buf_recv_size = 0; size_t buf_send_size = 0, buf_recv_size = 0;
if(dir & _NV_IOC_WRITE) { if (dir & _NV_IOC_WRITE) {
buf_send = argp; buf_send = argp;
buf_send_size = bufsize; buf_send_size = bufsize;
} }
if(dir & _NV_IOC_READ) { if (dir & _NV_IOC_READ) {
buf_recv = argp; buf_recv = argp;
buf_recv_size = bufsize; buf_recv_size = bufsize;
} }
ipcAddSendSmart(&c, g_nvIpcBufferSize, buf_send, buf_send_size, 0); const struct {
ipcAddRecvSmart(&c, g_nvIpcBufferSize, buf_recv, buf_recv_size, 0); u32 fd;
u32 request;
} in = { fd, request };
raw = ipcPrepareHeader(&c, sizeof(*raw)); u32 error = 0;
raw->magic = SFCI_MAGIC; Result rc = serviceDispatchInOut(_nvGetSessionForRequest(request), 1, in, error,
raw->cmd_id = 1; .buffer_attrs = {
raw->fd = fd; SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
raw->request = request; SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
},
.buffers = {
{ buf_send, buf_send_size },
{ buf_recv, buf_recv_size },
},
);
Result rc = serviceIpcDispatch(_nvGetSessionForRequest(request)); if (R_SUCCEEDED(rc))
rc = nvConvertError(error);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 error;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
rc = nvConvertError(resp->error);
}
return rc; return rc;
} }
Result nvIoctl2(u32 fd, u32 request, void* argp, const void* inbuf, size_t inbuf_size) { Result nvIoctl2(u32 fd, u32 request, void* argp, const void* inbuf, size_t inbuf_size)
IpcCommand c; {
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 fd;
u32 request;
} *raw;
size_t bufsize = _NV_IOC_SIZE(request); size_t bufsize = _NV_IOC_SIZE(request);
u32 dir = _NV_IOC_DIR(request); u32 dir = _NV_IOC_DIR(request);
void* buf_send = NULL, *buf_recv = NULL; void *buf_send = NULL, *buf_recv = NULL;
size_t buf_send_size = 0, buf_recv_size = 0; size_t buf_send_size = 0, buf_recv_size = 0;
if(dir & _NV_IOC_WRITE) { if (dir & _NV_IOC_WRITE) {
buf_send = argp; buf_send = argp;
buf_send_size = bufsize; buf_send_size = bufsize;
} }
if(dir & _NV_IOC_READ) { if (dir & _NV_IOC_READ) {
buf_recv = argp; buf_recv = argp;
buf_recv_size = bufsize; buf_recv_size = bufsize;
} }
ipcAddSendSmart(&c, g_nvIpcBufferSize, buf_send, buf_send_size, 0); const struct {
ipcAddSendSmart(&c, g_nvIpcBufferSize, inbuf, inbuf_size, 1);
ipcAddRecvSmart(&c, g_nvIpcBufferSize, buf_recv, buf_recv_size, 0);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 11;
raw->fd = fd;
raw->request = request;
Result rc = serviceIpcDispatch(_nvGetSessionForRequest(request));
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 error;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
rc = nvConvertError(resp->error);
}
return rc;
}
Result nvClose(u32 fd) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 fd; u32 fd;
} *raw; u32 request;
} in = { fd, request };
raw = ipcPrepareHeader(&c, sizeof(*raw)); u32 error = 0;
raw->magic = SFCI_MAGIC; Result rc = serviceDispatchInOut(_nvGetSessionForRequest(request), 11, in, error,
raw->cmd_id = 2; .buffer_attrs = {
raw->fd = fd; SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
},
.buffers = {
{ buf_send, buf_send_size },
{ inbuf, inbuf_size },
{ buf_recv, buf_recv_size },
},
);
Result rc = serviceIpcDispatch(&g_nvSrv); if (R_SUCCEEDED(rc))
rc = nvConvertError(error);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 error;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
rc = nvConvertError(resp->error);
}
return rc; return rc;
} }
Result nvQueryEvent(u32 fd, u32 event_id, Event *event_out) { Result nvClose(u32 fd)
IpcCommand c; {
ipcInitialize(&c); u32 error = 0;
Result rc = serviceDispatchInOut(&g_nvSrv, 2, fd, error);
struct { if (R_SUCCEEDED(rc))
u64 magic; rc = nvConvertError(error);
u64 cmd_id;
return rc;
}
Result nvQueryEvent(u32 fd, u32 event_id, Event *event_out)
{
const struct {
u32 fd; u32 fd;
u32 event_id; u32 event_id;
} *raw; } in = { fd, event_id };
raw = ipcPrepareHeader(&c, sizeof(*raw)); u32 error = 0;
raw->magic = SFCI_MAGIC; Handle event;
raw->cmd_id = 4; Result rc = serviceDispatchInOut(&g_nvSrv, 4, in, error,
raw->fd = fd; .out_handle_attrs = { SfOutHandleAttr_HipcCopy },
raw->event_id = event_id; .out_handles = &event,
);
Result rc = serviceIpcDispatch(&g_nvSrv); if (R_SUCCEEDED(rc))
rc = nvConvertError(error);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc))
IpcParsedCommand r; eventLoadRemote(event_out, event, true);
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 error;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
rc = nvConvertError(resp->error);
if (R_SUCCEEDED(rc))
eventLoadRemote(event_out, r.Handles[0], true);
}
return rc; return rc;
} }

View File

@ -1,837 +1,160 @@
// Copyright 2017 plutoo // Copyright 2017 plutoo
#include "types.h" #define NX_SERVICE_ASSUME_NON_DOMAIN
#include "result.h" #include "service_guard.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
#include "services/pm.h" #include "services/pm.h"
#include "services/sm.h"
static Service g_pmdmntSrv, g_pmshellSrv, g_pminfoSrv, g_pmbmSrv; #define PM_GENERATE_SERVICE_INIT(name) \
static u64 g_pmdmntRefCnt, g_pmshellRefCnt, g_pminfoRefCnt, g_pmbmRefCnt; static Service g_pm##name##Srv; \
\
Result pmdmntInitialize(void) NX_GENERATE_SERVICE_GUARD(pm##name); \
{ \
atomicIncrement64(&g_pmdmntRefCnt); Result _pm##name##Initialize(void) { \
return smGetService(&g_pm##name##Srv, "pm:"#name); \
if (serviceIsActive(&g_pmdmntSrv)) } \
return 0; \
void _pm##name##Cleanup(void) { \
return smGetService(&g_pmdmntSrv, "pm:dmnt"); serviceClose(&g_pm##name##Srv); \
} \
\
Service* pm##name##GetServiceSession(void) { \
return &g_pm##name##Srv; \
} }
void pmdmntExit(void) PM_GENERATE_SERVICE_INIT(dmnt);
{ PM_GENERATE_SERVICE_INIT(shell);
if (atomicDecrement64(&g_pmdmntRefCnt) == 0) { PM_GENERATE_SERVICE_INIT(info);
serviceClose(&g_pmdmntSrv); PM_GENERATE_SERVICE_INIT(bm);
}
}
Service* pmdmntGetServiceSession(void) {
return &g_pmdmntSrv;
}
Result pminfoInitialize(void)
{
atomicIncrement64(&g_pminfoRefCnt);
if (serviceIsActive(&g_pminfoSrv))
return 0;
return smGetService(&g_pminfoSrv, "pm:info");
}
void pminfoExit(void)
{
if (atomicDecrement64(&g_pminfoRefCnt) == 0) {
serviceClose(&g_pminfoSrv);
}
}
Service* pminfoGetServiceSession(void)
{
return &g_pminfoSrv;
}
Result pmshellInitialize(void)
{
atomicIncrement64(&g_pmshellRefCnt);
if (serviceIsActive(&g_pmshellSrv))
return 0;
return smGetService(&g_pmshellSrv, "pm:shell");
}
void pmshellExit(void)
{
if (atomicDecrement64(&g_pmshellRefCnt) == 0) {
serviceClose(&g_pmshellSrv);
}
}
Service* pmshellGetServiceSession(void)
{
return &g_pmshellSrv;
}
Result pmbmInitialize(void)
{
atomicIncrement64(&g_pmbmRefCnt);
if (serviceIsActive(&g_pmbmSrv))
return 0;
return smGetService(&g_pmbmSrv, "pm:bm");
}
void pmbmExit(void)
{
if (atomicDecrement64(&g_pmbmRefCnt) == 0) {
serviceClose(&g_pmbmSrv);
}
}
Service* pmbmGetServiceSession(void)
{
return &g_pmbmSrv;
}
Result pmdmntGetDebugProcesses(u32* out_count, u64* out_pids, size_t max_pids) { Result pmdmntGetDebugProcesses(u32* out_count, u64* out_pids, size_t max_pids) {
IpcCommand c; const u64 cmd_id = hosversionAtLeast(5,0,0) ? 0 : 1;
ipcInitialize(&c); return serviceDispatchOut(&g_pmdmntSrv, cmd_id, *out_count,
ipcAddRecvBuffer(&c, out_pids, sizeof(*out_pids) * max_pids, BufferType_Normal); .buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
struct { },
u64 magic; .buffers = {
u64 cmd_id; { out_pids, max_pids * sizeof(*out_pids) },
} *raw; },
);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 0 : 1;
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 out_count;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (out_count) *out_count = resp->out_count;
}
}
return rc;
} }
Result pmdmntStartProcess(u64 pid) { Result pmdmntStartProcess(u64 pid) {
IpcCommand c; const u64 cmd_id = hosversionAtLeast(5,0,0) ? 1 : 2;
ipcInitialize(&c); return serviceDispatchIn(&g_pmdmntSrv, cmd_id, pid);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 1 : 2;
raw->pid = pid;
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmdmntGetTitlePid(u64* pid_out, u64 title_id) { Result pmdmntGetTitlePid(u64* pid_out, u64 title_id) {
IpcCommand c; const u64 cmd_id = hosversionAtLeast(5,0,0) ? 2 : 3;
ipcInitialize(&c); return serviceDispatchInOut(&g_pmdmntSrv, cmd_id, title_id, *pid_out);
struct {
u64 magic;
u64 cmd_id;
u64 title_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 2 : 3;
raw->title_id = title_id;
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 pid;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*pid_out = resp->pid;
}
}
return rc;
} }
Result pmdmntEnableDebugForTitleId(Handle* handle_out, u64 title_id) { Result pmdmntEnableDebugForTitleId(Event* out_event, u64 title_id) {
IpcCommand c; const u64 cmd_id = hosversionAtLeast(5,0,0) ? 3 : 4;
ipcInitialize(&c); Handle event = INVALID_HANDLE;
Result rc = serviceDispatchIn(&g_pmdmntSrv, cmd_id, title_id,
struct { .out_handle_attrs = { SfOutHandleAttr_HipcCopy },
u64 magic; .out_handles = &event,
u64 cmd_id; );
u64 title_id; if (R_SUCCEEDED(rc))
} *raw; eventLoadRemote(out_event, event, true);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 3 : 4;
raw->title_id = title_id;
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*handle_out = r.Handles[0];
}
}
return rc;
}
Result pminfoGetTitleId(u64* title_id_out, u64 pid) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->pid = pid;
Result rc = serviceIpcDispatch(&g_pminfoSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 title_id;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*title_id_out = resp->title_id;
}
}
return rc; return rc;
} }
Result pmdmntGetApplicationPid(u64* pid_out) { Result pmdmntGetApplicationPid(u64* pid_out) {
IpcCommand c; const u64 cmd_id = hosversionAtLeast(5,0,0) ? 4 : 5;
ipcInitialize(&c); return serviceDispatchOut(&g_pmdmntSrv, cmd_id, *pid_out);
}
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 4 : 5;
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 pid;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*pid_out = resp->pid;
}
}
Result pmdmntEnableDebugForApplication(Event* out_event) {
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 5 : 6;
Handle event = INVALID_HANDLE;
Result rc = serviceDispatch(&g_pmdmntSrv, cmd_id,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
.out_handles = &event,
);
if (R_SUCCEEDED(rc))
eventLoadRemote(out_event, event, true);
return rc; return rc;
} }
Result pmdmntEnableDebugForApplication(Handle* handle_out) { Result pmdmntDisableDebug(u32 which) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 5 : 6;
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*handle_out = r.Handles[0];
}
}
return rc;
}
Result pmdmntDisableDebug(void) {
if (hosversionBefore(6,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(6,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchIn(&g_pmdmntSrv, 6, which);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 6;
Result rc = serviceIpcDispatch(&g_pmdmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmshellLaunchProcess(u32 launch_flags, u64 titleID, u64 storageID, u64 *pid) { Result pmshellLaunchProcess(u32 launch_flags, u64 titleID, u64 storageID, u64 *pid) {
IpcCommand c; const struct {
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 launch_flags; u32 launch_flags;
u64 titleID; u64 titleID;
u64 storageID; u64 storageID;
} *raw; } in = { launch_flags, titleID, storageID };
return serviceDispatchInOut(&g_pmshellSrv, 0, in, *pid);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->launch_flags = launch_flags;
raw->titleID = titleID;
raw->storageID = storageID;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 pid;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && pid) *pid = resp->pid;
}
return rc;
} }
Result pmshellTerminateProcessByProcessId(u64 processID) { Result pmshellTerminateProcessByProcessId(u64 processID) {
IpcCommand c; return serviceDispatchIn(&g_pmshellSrv, 1, processID);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 processID;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->processID = processID;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmshellTerminateProcessByTitleId(u64 titleID) { Result pmshellTerminateProcessByTitleId(u64 titleID) {
IpcCommand c; return serviceDispatchIn(&g_pmshellSrv, 2, titleID);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 titleID;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2;
raw->titleID = titleID;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmshellGetProcessEvent(Event* out) { Result pmshellGetProcessEvent(Event* out_event) {
IpcCommand c; Handle event = INVALID_HANDLE;
ipcInitialize(&c); Result rc = serviceDispatch(&g_pmshellSrv, 3,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
struct { .out_handles = &event,
u64 magic; );
u64 cmd_id; if (R_SUCCEEDED(rc))
} *raw; eventLoadRemote(out_event, event, true);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 3;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
eventLoadRemote(out, r.Handles[0], true);
}
}
return rc; return rc;
} }
Result pmshellGetProcessEventInfo(PmProcessEventInfo* out) { Result pmshellGetProcessEventInfo(PmProcessEventInfo* out) {
IpcCommand c; _Static_assert(sizeof(out->event) == sizeof(u32), "PmProcessEvent");
ipcInitialize(&c); return serviceDispatchOut(&g_pmshellSrv, 4, *out);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 4;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 event;
u32 pad;
u64 process_id;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (out) {
out->event = (PmProcessEvent)resp->event;
out->process_id = resp->process_id;
}
}
}
return rc;
} }
Result pmshellFinalizeDeadProcess(u64 pid) { Result pmshellFinalizeDeadProcess(u64 pid) {
if (hosversionAtLeast(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionAtLeast(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchIn(&g_pmshellSrv, 5, pid);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
raw->pid = pid;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmshellClearProcessExceptionOccurred(u64 pid) { Result pmshellClearProcessExceptionOccurred(u64 pid) {
if (hosversionAtLeast(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionAtLeast(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchIn(&g_pmshellSrv, 6, pid);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 6;
raw->pid = pid;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmshellNotifyBootFinished(void) { Result pmshellNotifyBootFinished(void) {
IpcCommand c; const u64 cmd_id = hosversionAtLeast(5,0,0) ? 5 : 7;
ipcInitialize(&c); return serviceDispatch(&g_pmshellSrv, cmd_id);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 5 : 7;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmshellGetApplicationPid(u64* pid_out) { Result pmshellGetApplicationPid(u64* pid_out) {
IpcCommand c; const u64 cmd_id = hosversionAtLeast(5,0,0) ? 6 : 8;
ipcInitialize(&c); return serviceDispatchOut(&g_pmshellSrv, cmd_id, *pid_out);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 6 : 8;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 pid;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*pid_out = resp->pid;
}
}
return rc;
} }
Result pmshellBoostSystemMemoryResourceLimit(u64 boost_size) { Result pmshellBoostSystemMemoryResourceLimit(u64 boost_size) {
if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const u64 cmd_id = hosversionAtLeast(5,0,0) ? 7 : 9;
IpcCommand c; return serviceDispatchIn(&g_pmshellSrv, cmd_id, boost_size);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 boost_size;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(5,0,0) ? 7 : 9;
raw->boost_size = boost_size;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmshellBoostSystemThreadResourceLimit(void) { Result pmshellBoostSystemThreadResourceLimit(void) {
if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatch(&g_pmshellSrv, 8);
}
IpcCommand c; Result pminfoGetTitleId(u64* title_id_out, u64 pid) {
ipcInitialize(&c); return serviceDispatchInOut(&g_pminfoSrv, 0, pid, *title_id_out);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 8;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result pmbmGetBootMode(PmBootMode *out) { Result pmbmGetBootMode(PmBootMode *out) {
IpcCommand c; _Static_assert(sizeof(*out) == sizeof(u32), "PmBootMode");
ipcInitialize(&c); return serviceDispatchOut(&g_pmbmSrv, 0, *out);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&g_pmbmSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 boot_mode;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) {
*out = (PmBootMode)resp->boot_mode;
}
}
return rc;
} }
Result pmbmSetMaintenanceBoot(void) { Result pmbmSetMaintenanceBoot(void) {
IpcCommand c; return serviceDispatch(&g_pmbmSrv, 1);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
Result rc = serviceIpcDispatch(&g_pmbmSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }

View File

@ -1,135 +1,80 @@
#include "types.h" #define NX_SERVICE_ASSUME_NON_DOMAIN
#include "result.h" #include "service_guard.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "kernel/event.h" #include "kernel/event.h"
#include "services/psm.h" #include "services/psm.h"
#include "services/sm.h"
static Service g_psmSrv; static Service g_psmSrv;
static u64 g_refCnt;
static Result _psmOpenSession(Service* out); static Result _psmOpenSession(Service* srv_out);
static Result _psmBindStateChangeEvent(PsmSession* s, Event* event_out); static Result _psmBindStateChangeEvent(PsmSession* s, Event* event_out);
static Result _psmSetChargerTypeChangeEventEnabled(PsmSession* s, bool flag); static Result _psmSetChargerTypeChangeEventEnabled(PsmSession* s, bool flag);
static Result _psmSetPowerSupplyChangeEventEnabled(PsmSession* s, bool flag); static Result _psmSetPowerSupplyChangeEventEnabled(PsmSession* s, bool flag);
static Result _psmSetBatteryVoltageStateChangeEventEnabled(PsmSession* s, bool flag); static Result _psmSetBatteryVoltageStateChangeEventEnabled(PsmSession* s, bool flag);
Result psmInitialize(void) { NX_GENERATE_SERVICE_GUARD(psm);
Result rc = 0;
atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_psmSrv)) Result _psmInitialize(void) {
return 0; return smGetService(&g_psmSrv, "psm");
rc = smGetService(&g_psmSrv, "psm");
if (R_FAILED(rc)) psmExit();
return rc;
} }
void psmExit(void) { void _psmCleanup(void) {
if (atomicDecrement64(&g_refCnt) == 0) { serviceClose(&g_psmSrv);
serviceClose(&g_psmSrv);
}
} }
Service* psmGetServiceSession(void) { Service* psmGetServiceSession(void) {
return &g_psmSrv; return &g_psmSrv;
} }
static Result _psmGetOutU32(u64 cmd_id, u32 *out) { static Result _psmCmdNoIO(Service* srv, u32 cmd_id) {
IpcCommand c; return serviceDispatch(srv, cmd_id);
ipcInitialize(&c); }
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_psmSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(&g_psmSrv);
if(R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct { static Result _psmCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) {
u64 magic; Handle event = INVALID_HANDLE;
u64 result; Result rc = serviceDispatch(srv, cmd_id,
u32 out; .out_handle_attrs = { SfOutHandleAttr_HipcCopy },
} *resp; .out_handles = &event,
);
serviceIpcParse(&g_psmSrv, &r, sizeof(*resp)); if (R_SUCCEEDED(rc))
resp = r.Raw; eventLoadRemote(out_event, event, autoclear);
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*out = resp->out;
}
}
return rc; return rc;
} }
static Result _psmCmdInU8NoOut(Service* srv, u8 inval, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, inval);
}
static Result _psmCmdInBoolNoOut(Service* srv, bool inval, u32 cmd_id) {
return _psmCmdInU8NoOut(srv, inval!=0, cmd_id);
}
static Result _psmCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
Result psmGetBatteryChargePercentage(u32 *out) { Result psmGetBatteryChargePercentage(u32 *out) {
return _psmGetOutU32(0, out); return _psmCmdNoInOutU32(&g_psmSrv, out, 0);
} }
Result psmGetChargerType(ChargerType *out) { Result psmGetChargerType(ChargerType *out) {
return _psmGetOutU32(1, out); return _psmCmdNoInOutU32(&g_psmSrv, out, 1);
} }
Result psmGetBatteryVoltageState(PsmBatteryVoltageState *out) { Result psmGetBatteryVoltageState(PsmBatteryVoltageState *out) {
u32 state; u32 state;
Result rc = _psmGetOutU32(12, &state); Result rc = _psmCmdNoInOutU32(&g_psmSrv, &state, 12);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc) && out) *out = state;
*out = (PsmBatteryVoltageState)state;
}
return rc; return rc;
} }
static Result _psmOpenSession(Service* out) { static Result _psmOpenSession(Service* srv_out) {
IpcCommand c; return serviceDispatch(&g_psmSrv, 7,
ipcInitialize(&c); .out_num_objects = 1,
.out_objects = srv_out,
struct { );
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_psmSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 7;
Result rc = serviceIpcDispatch(&g_psmSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_psmSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc))
serviceCreateSubservice(out, &g_psmSrv, &r, 0);
}
return rc;
} }
Result psmBindStateChangeEvent(PsmSession* s, bool ChargerType, bool PowerSupply, bool BatteryVoltage) { Result psmBindStateChangeEvent(PsmSession* s, bool ChargerType, bool PowerSupply, bool BatteryVoltage) {
@ -162,71 +107,12 @@ Result psmWaitStateChangeEvent(PsmSession* s, u64 timeout) {
} }
static Result _psmBindStateChangeEvent(PsmSession* s, Event *event_out) { static Result _psmBindStateChangeEvent(PsmSession* s, Event *event_out) {
IpcCommand c; return _psmCmdGetEvent(&s->s, event_out, false, 0);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&s->s);
if(R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
eventLoadRemote(event_out, r.Handles[0], false);
}
}
return rc;
} }
Result psmUnbindStateChangeEvent(PsmSession* s) { Result psmUnbindStateChangeEvent(PsmSession* s) {
IpcCommand c; Result rc=0;
ipcInitialize(&c); if (serviceIsActive(&s->s)) rc = _psmCmdNoIO(&s->s, 1);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
Result rc = serviceIpcDispatch(&s->s);
if(R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
eventClose(&s->StateChangeEvent); eventClose(&s->StateChangeEvent);
serviceClose(&s->s); serviceClose(&s->s);
@ -234,49 +120,18 @@ Result psmUnbindStateChangeEvent(PsmSession* s) {
return rc; return rc;
} }
static Result _psmSetEventEnabled(PsmSession* s, u64 cmd_id, bool flag) { static Result _psmSetEventEnabled(PsmSession* s, bool flag, u32 cmd_id) {
IpcCommand c; return _psmCmdInBoolNoOut(&s->s, flag, cmd_id);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 flag;
} *raw;
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->flag = (flag != 0);
Result rc = serviceIpcDispatch(&s->s);
if(R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
static Result _psmSetChargerTypeChangeEventEnabled(PsmSession* s, bool flag) { static Result _psmSetChargerTypeChangeEventEnabled(PsmSession* s, bool flag) {
return _psmSetEventEnabled(s, 2, flag); return _psmSetEventEnabled(s, flag, 2);
} }
static Result _psmSetPowerSupplyChangeEventEnabled(PsmSession* s, bool flag) { static Result _psmSetPowerSupplyChangeEventEnabled(PsmSession* s, bool flag) {
return _psmSetEventEnabled(s, 3, flag); return _psmSetEventEnabled(s, flag, 3);
} }
static Result _psmSetBatteryVoltageStateChangeEventEnabled(PsmSession* s, bool flag) { static Result _psmSetBatteryVoltageStateChangeEventEnabled(PsmSession* s, bool flag) {
return _psmSetEventEnabled(s, 4, flag); return _psmSetEventEnabled(s, flag, 4);
} }

View File

@ -1,86 +1,60 @@
// Copyright 2018 SciresM // Copyright 2018 SciresM
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h> #include <string.h>
#include "types.h" #include "service_guard.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
#include "services/ro.h" #include "services/ro.h"
#include "services/sm.h"
static Service g_roSrv, g_ro1Srv, g_dmntSrv; static Service g_roSrv, g_ro1Srv, g_dmntSrv;
static u64 g_roRefCnt, g_ro1RefCnt, g_dmntRefCnt;
static Result _rosrvInitialize(Service* srv); NX_GENERATE_SERVICE_GUARD(ldrRo);
static Result _rosrvLoadNro(Service* srv, u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size); NX_GENERATE_SERVICE_GUARD(ro1);
static Result _rosrvUnloadNro(Service* srv, u64 nro_address); NX_GENERATE_SERVICE_GUARD(roDmnt);
static Result _rosrvLoadNrr(Service* srv, u64 cmd_id, u64 nrr_address, u64 nrr_size);
static Result _rosrvUnloadNrr(Service* srv, u64 nrr_address);
Result ldrRoInitialize(void) { NX_INLINE Result _rosrvInitialize(Service* srv);
atomicIncrement64(&g_roRefCnt); NX_INLINE Result _rosrvLoadNro(Service* srv, u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
NX_INLINE Result _rosrvUnloadNro(Service* srv, u64 nro_address);
if (serviceIsActive(&g_roSrv)) NX_INLINE Result _rosrvLoadNrr(Service* srv, u64 cmd_id, u64 nrr_address, u64 nrr_size);
return 0; NX_INLINE Result _rosrvUnloadNrr(Service* srv, u64 nrr_address);
Result _ldrRoInitialize(void) {
Result rc = smGetService(&g_roSrv, "ldr:ro"); Result rc = smGetService(&g_roSrv, "ldr:ro");
if (R_SUCCEEDED(rc))
if (R_SUCCEEDED(rc)) {
rc = _rosrvInitialize(&g_roSrv); rc = _rosrvInitialize(&g_roSrv);
}
return rc; return rc;
} }
void ldrRoExit(void) { void _ldrRoCleanup(void) {
if (atomicDecrement64(&g_roRefCnt) == 0) serviceClose(&g_roSrv);
serviceClose(&g_roSrv);
} }
Service* ldrRoGetServiceSession(void) { Service* ldrRoGetServiceSession(void) {
return &g_roSrv; return &g_roSrv;
} }
Result ro1Initialize(void) { Result _ro1Initialize(void) {
if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
atomicIncrement64(&g_ro1RefCnt);
if (serviceIsActive(&g_ro1Srv))
return 0;
Result rc = smGetService(&g_ro1Srv, "ro:1"); Result rc = smGetService(&g_ro1Srv, "ro:1");
if (R_SUCCEEDED(rc))
if (R_SUCCEEDED(rc)) {
rc = _rosrvInitialize(&g_ro1Srv); rc = _rosrvInitialize(&g_ro1Srv);
}
return rc; return rc;
} }
void ro1Exit(void) { void _ro1Cleanup(void) {
if (atomicDecrement64(&g_ro1RefCnt) == 0) serviceClose(&g_ro1Srv);
serviceClose(&g_ro1Srv);
} }
Service* ro1GetServiceSession(void) { Service* ro1GetServiceSession(void) {
return &g_ro1Srv; return &g_ro1Srv;
} }
Result roDmntInitialize(void) { Result _roDmntInitialize(void) {
if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
atomicIncrement64(&g_dmntRefCnt);
if (serviceIsActive(&g_dmntSrv))
return 0;
return smGetService(&g_dmntSrv, "ro:dmnt"); return smGetService(&g_dmntSrv, "ro:dmnt");
} }
void roDmntExit(void) { void _roDmntCleanup(void) {
if (atomicDecrement64(&g_dmntRefCnt) == 0) serviceClose(&g_dmntSrv);
serviceClose(&g_dmntSrv);
} }
Service* roDmntGetServiceSession(void) { Service* roDmntGetServiceSession(void) {
@ -88,198 +62,46 @@ Service* roDmntGetServiceSession(void) {
} }
Result _rosrvInitialize(Service* srv) { Result _rosrvInitialize(Service* srv) {
IpcCommand c; return serviceDispatch(srv, 4,
ipcInitialize(&c); .in_num_handles = 1,
ipcSendHandleCopy(&c, CUR_PROCESS_HANDLE); .in_handles = { CUR_PROCESS_HANDLE },
ipcSendPid(&c); );
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 4;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result _rosrvLoadNro(Service* srv, u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { Result _rosrvLoadNro(Service* srv, u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
IpcCommand c; const struct {
ipcInitialize(&c); u64 pid_placeholder;
ipcSendPid(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
u64 nro_address; u64 nro_address;
u64 nro_size; u64 nro_size;
u64 bss_address; u64 bss_address;
u64 bss_size; u64 bss_size;
} *raw; } in = { 0, nro_address, nro_size, bss_address, bss_size };
return serviceDispatchInOut(srv, 0, in, *out_address, .in_send_pid = true);
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->pid = 0;
raw->nro_address = nro_address;
raw->nro_size = nro_size;
raw->bss_address = bss_address;
raw->bss_size = bss_size;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u64 out_address;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (out_address) *out_address = resp->out_address;
}
}
return rc;
} }
Result _rosrvUnloadNro(Service* srv, u64 nro_address) { Result _rosrvUnloadNro(Service* srv, u64 nro_address) {
IpcCommand c; const struct {
ipcInitialize(&c); u64 pid_placeholder;
ipcSendPid(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
u64 nro_address; u64 nro_address;
} *raw; } in = { 0, nro_address };
return serviceDispatchIn(srv, 1, in, .in_send_pid = true);
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->pid = 0;
raw->nro_address = nro_address;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result _rosrvLoadNrr(Service* srv, u64 cmd_id, u64 nrr_address, u64 nrr_size) { Result _rosrvLoadNrr(Service* srv, u64 cmd_id, u64 nrr_address, u64 nrr_size) {
IpcCommand c; const struct {
ipcInitialize(&c); u64 pid_placeholder;
ipcSendPid(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
u64 nrr_address; u64 nrr_address;
u64 nrr_size; u64 nrr_size;
} *raw; } in = { 0, nrr_address, nrr_size };
return serviceDispatchIn(srv, cmd_id, in, .in_send_pid = true);
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
raw->pid = 0;
raw->nrr_address = nrr_address;
raw->nrr_size = nrr_size;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result _rosrvUnloadNrr(Service* srv, u64 nrr_address) { Result _rosrvUnloadNrr(Service* srv, u64 nrr_address) {
IpcCommand c; const struct {
ipcInitialize(&c); u64 pid_placeholder;
ipcSendPid(&c);
struct {
u64 magic;
u64 cmd_id;
u64 pid;
u64 nrr_address; u64 nrr_address;
} *raw; } in = { 0, nrr_address };
return serviceDispatchIn(srv, 3, in, .in_send_pid = true);
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 3;
raw->pid = 0;
raw->nrr_address = nrr_address;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result ldrRoLoadNro(u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { Result ldrRoLoadNro(u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
@ -326,41 +148,12 @@ Result ro1LoadNrrEx(u64 nrr_address, u64 nrr_size) {
} }
Result roDmntGetModuleInfos(u64 pid, LoaderModuleInfo *out_module_infos, size_t max_out_modules, u32 *num_out) { Result roDmntGetModuleInfos(u64 pid, LoaderModuleInfo *out_module_infos, size_t max_out_modules, u32 *num_out) {
IpcCommand c; return serviceDispatchInOut(&g_dmntSrv, 0, pid, *num_out,
ipcInitialize(&c); .buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
ipcAddRecvBuffer(&c, out_module_infos, max_out_modules * sizeof(*out_module_infos), BufferType_Normal); },
.buffers = {
struct { { out_module_infos, max_out_modules * sizeof(*out_module_infos) },
u64 magic; },
u64 cmd_id; );
u64 pid;
} *raw;
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->pid = pid;
Result rc = serviceIpcDispatch(&g_dmntSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 num_out;
} *resp;
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && num_out != NULL) {
*num_out = resp->num_out;
}
}
return rc;
} }

View File

@ -0,0 +1,56 @@
#pragma once
#include "types.h"
#include "result.h"
#include "kernel/mutex.h"
#include "sf/service.h"
#include "services/sm.h"
typedef struct ServiceGuard {
Mutex mutex;
u32 refCount;
} ServiceGuard;
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
{
mutexLock(&g->mutex);
return (g->refCount++) == 0;
}
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
{
if (R_FAILED(rc)) {
cleanupFunc();
--g->refCount;
}
mutexUnlock(&g->mutex);
return rc;
}
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
{
mutexLock(&g->mutex);
if (g->refCount && (--g->refCount) == 0)
cleanupFunc();
mutexUnlock(&g->mutex);
}
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
\
static ServiceGuard g_##name##Guard; \
NX_INLINE Result _##name##Initialize _paramdecl; \
static void _##name##Cleanup(void); \
\
Result name##Initialize _paramdecl \
{ \
Result rc = 0; \
if (serviceGuardBeginInit(&g_##name##Guard)) \
rc = _##name##Initialize _parampass; \
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
} \
\
void name##Exit(void) \
{ \
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
}
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())

View File

@ -1,24 +1,12 @@
/** #define NX_SERVICE_ASSUME_NON_DOMAIN
* @file set.h
* @brief Settings services IPC wrapper.
* @author plutoo
* @author yellows8
* @copyright libnx Authors
*/
#include <string.h> #include <string.h>
#include "types.h" #include "service_guard.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h" #include "runtime/hosversion.h"
#include "services/set.h" #include "services/set.h"
#include "services/sm.h"
#include "services/applet.h" #include "services/applet.h"
static Service g_setSrv; static Service g_setSrv;
static Service g_setsysSrv; static Service g_setsysSrv;
static u64 g_refCnt;
static u64 g_refCntSys;
static bool g_setLanguageCodesInitialized; static bool g_setLanguageCodesInitialized;
static u64 g_setLanguageCodes[0x40]; static u64 g_setLanguageCodes[0x40];
@ -26,50 +14,83 @@ static s32 g_setLanguageCodesTotal;
static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode); static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode);
Result setInitialize(void) NX_GENERATE_SERVICE_GUARD(set);
{
atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_setSrv))
return 0;
Result _setInitialize(void) {
g_setLanguageCodesInitialized = 0; g_setLanguageCodesInitialized = 0;
return smGetService(&g_setSrv, "set"); return smGetService(&g_setSrv, "set");
} }
void setExit(void) void _setCleanup(void) {
{ serviceClose(&g_setSrv);
if (atomicDecrement64(&g_refCnt) == 0) {
serviceClose(&g_setSrv);
}
} }
Service* setGetServiceSession(void) { Service* setGetServiceSession(void) {
return &g_setSrv; return &g_setSrv;
} }
Result setsysInitialize(void) NX_GENERATE_SERVICE_GUARD(setsys);
{
atomicIncrement64(&g_refCntSys);
if (serviceIsActive(&g_setsysSrv))
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
Result _setsysInitialize(void) {
return smGetService(&g_setsysSrv, "set:sys"); return smGetService(&g_setsysSrv, "set:sys");
} }
void setsysExit(void) void _setsysCleanup(void) {
{ serviceClose(&g_setsysSrv);
if (atomicDecrement64(&g_refCntSys) == 0) {
serviceClose(&g_setsysSrv);
}
} }
Service* setsysGetSessionService(void) { Service* setsysGetServiceSession(void) {
return &g_setsysSrv; return &g_setsysSrv;
} }
static Result _setCmdGetHandle(Service* srv, Handle* handle_out, u32 cmd_id) {
return serviceDispatch(srv, cmd_id,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
.out_handles = handle_out,
);
}
static Result _setCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) {
Handle tmp_handle = INVALID_HANDLE;
Result rc = 0;
rc = _setCmdGetHandle(srv, &tmp_handle, cmd_id);
if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, autoclear);
return rc;
}
static Result _setCmdNoInOut64(Service* srv, u64 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _setCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _setCmdNoInOutU8(Service* srv, u8 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _setCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) {
u8 tmp=0;
Result rc = _setCmdNoInOutU8(srv, &tmp, cmd_id);
if (R_SUCCEEDED(rc) && out) *out = tmp!=0;
return rc;
}
static Result _setCmdInU8NoOut(Service* srv, u8 inval, u64 cmd_id) {
return serviceDispatchIn(srv, cmd_id, inval);
}
static Result _setCmdInBoolNoOut(Service* srv, bool inval, u32 cmd_id) {
return _setCmdInU8NoOut(srv, inval!=0, cmd_id);
}
static Result _setCmdInU32NoOut(Service* srv, u32 inval, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, inval);
}
static Result setInitializeLanguageCodesCache(void) { static Result setInitializeLanguageCodesCache(void) {
if (g_setLanguageCodesInitialized) return 0; if (g_setLanguageCodesInitialized) return 0;
Result rc = 0; Result rc = 0;
@ -84,7 +105,7 @@ static Result setInitializeLanguageCodesCache(void) {
return rc; return rc;
} }
Result setMakeLanguage(u64 LanguageCode, s32 *Language) { Result setMakeLanguage(u64 LanguageCode, SetLanguage *Language) {
Result rc = setInitializeLanguageCodesCache(); Result rc = setInitializeLanguageCodesCache();
if (R_FAILED(rc)) return rc; if (R_FAILED(rc)) return rc;
@ -100,7 +121,7 @@ Result setMakeLanguage(u64 LanguageCode, s32 *Language) {
return rc; return rc;
} }
Result setMakeLanguageCode(s32 Language, u64 *LanguageCode) { Result setMakeLanguageCode(SetLanguage Language, u64 *LanguageCode) {
Result rc = setInitializeLanguageCodesCache(); Result rc = setInitializeLanguageCodesCache();
if (R_FAILED(rc)) return rc; if (R_FAILED(rc)) return rc;
@ -126,43 +147,10 @@ Result setGetSystemLanguage(u64 *LanguageCode) {
} }
Result setGetLanguageCode(u64 *LanguageCode) { Result setGetLanguageCode(u64 *LanguageCode) {
IpcCommand c; return _setCmdNoInOut64(&g_setSrv, LanguageCode, 0);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&g_setSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 LanguageCode;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode;
}
return rc;
} }
Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries) { Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries) {
IpcCommand c;
ipcInitialize(&c);
Result rc=0; Result rc=0;
bool new_cmd = hosversionAtLeast(4,0,0); bool new_cmd = hosversionAtLeast(4,0,0);
@ -175,260 +163,38 @@ Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size
if (max_entries > (size_t)tmptotal) max_entries = (size_t)tmptotal; if (max_entries > (size_t)tmptotal) max_entries = (size_t)tmptotal;
} }
size_t bufsize = max_entries*sizeof(u64); return serviceDispatchOut(&g_setSrv, new_cmd ? 5 : 1, *total_entries,
.buffer_attrs = { (new_cmd ? SfBufferAttr_HipcMapAlias : SfBufferAttr_HipcPointer) | SfBufferAttr_Out },
if (!new_cmd) { .buffers = { { LanguageCodes, max_entries*sizeof(u64) } },
ipcAddRecvStatic(&c, LanguageCodes, bufsize, 0); );
}
else {
ipcAddRecvBuffer(&c, LanguageCodes, bufsize, 0);
}
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = new_cmd ? 5 : 1;
rc = serviceIpcDispatch(&g_setSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
s32 total_entries;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries;
}
return rc;
} }
static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode) { static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode) {
IpcCommand c; return serviceDispatchInOut(&g_setSrv, 2, Language, *LanguageCode);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
s32 Language;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2;
raw->Language = Language;
Result rc = serviceIpcDispatch(&g_setSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 LanguageCode;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode;
}
return rc;
} }
Result setGetAvailableLanguageCodeCount(s32 *total) { Result setGetAvailableLanguageCodeCount(s32 *total) {
IpcCommand c; Result rc = _setCmdNoInOutU32(&g_setSrv, (u32*)total, hosversionAtLeast(4,0,0) ? 6 : 3);
ipcInitialize(&c); if (R_SUCCEEDED(rc) && total && *total < 0) *total = 0;
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = hosversionAtLeast(4,0,0) ? 6 : 3;
Result rc = serviceIpcDispatch(&g_setSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
s32 total;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total) {
*total = resp->total;
if (*total < 0) *total = 0;
}
}
return rc; return rc;
} }
Result setGetRegionCode(SetRegion *out) { Result setGetRegionCode(SetRegion *out) {
IpcCommand c; s32 code=0;
ipcInitialize(&c); Result rc = _setCmdNoInOutU32(&g_setSrv, (u32*)&code, 4);
if (R_SUCCEEDED(rc) && out) *out = code;
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 4;
Result rc = serviceIpcDispatch(&g_setSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
s32 RegionCode;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) *out = resp->RegionCode;
}
return rc; return rc;
} }
Result setsysGetColorSetId(ColorSetId *out) Result setsysGetColorSetId(ColorSetId *out) {
{ u32 color_set=0;
IpcCommand c; Result rc = _setCmdNoInOutU32(&g_setsysSrv, &color_set, 23);
ipcInitialize(&c); if (R_SUCCEEDED(rc) && out) *out = color_set;
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 23;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 color_set;
} *resp = r.Raw;
*out = resp->color_set;
rc = resp->result;
}
return rc; return rc;
} }
Result setsysSetColorSetId(ColorSetId id) Result setsysSetColorSetId(ColorSetId id) {
{ return _setCmdInU32NoOut(&g_setsysSrv, id, 24);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
s32 id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 24;
raw->id = id;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size) {
char send_name[SET_MAX_NAME_SIZE];
char send_item_key[SET_MAX_NAME_SIZE];
memset(send_name, 0, SET_MAX_NAME_SIZE);
memset(send_item_key, 0, SET_MAX_NAME_SIZE);
strncpy(send_name, name, SET_MAX_NAME_SIZE-1);
strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1);
IpcCommand c;
ipcInitialize(&c);
ipcAddSendStatic(&c, send_name, SET_MAX_NAME_SIZE, 0);
ipcAddSendStatic(&c, send_item_key, SET_MAX_NAME_SIZE, 0);
ipcAddRecvBuffer(&c, value_out, value_out_size, 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 38;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u64 *size_out) { Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u64 *size_out) {
@ -439,178 +205,66 @@ Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u6
memset(send_item_key, 0, SET_MAX_NAME_SIZE); memset(send_item_key, 0, SET_MAX_NAME_SIZE);
strncpy(send_name, name, SET_MAX_NAME_SIZE-1); strncpy(send_name, name, SET_MAX_NAME_SIZE-1);
strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1); strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1);
return serviceDispatchOut(&g_setsysSrv, 37, *size_out,
.buffer_attrs = {
SfBufferAttr_HipcPointer | SfBufferAttr_In,
SfBufferAttr_HipcPointer | SfBufferAttr_In,
},
.buffers = {
{ send_name, SET_MAX_NAME_SIZE },
{ send_item_key, SET_MAX_NAME_SIZE },
},
);
}
Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size, u64 *size_out) {
char send_name[SET_MAX_NAME_SIZE];
char send_item_key[SET_MAX_NAME_SIZE];
IpcCommand c; memset(send_name, 0, SET_MAX_NAME_SIZE);
ipcInitialize(&c); memset(send_item_key, 0, SET_MAX_NAME_SIZE);
ipcAddSendStatic(&c, send_name, SET_MAX_NAME_SIZE, 0); strncpy(send_name, name, SET_MAX_NAME_SIZE-1);
ipcAddSendStatic(&c, send_item_key, SET_MAX_NAME_SIZE, 0); strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1);
struct { return serviceDispatchOut(&g_setsysSrv, 38, *size_out,
u64 magic; .buffer_attrs = {
u64 cmd_id; SfBufferAttr_HipcPointer | SfBufferAttr_In,
} *raw; SfBufferAttr_HipcPointer | SfBufferAttr_In,
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
raw = ipcPrepareHeader(&c, sizeof(*raw)); },
.buffers = {
raw->magic = SFCI_MAGIC; { send_name, SET_MAX_NAME_SIZE },
raw->cmd_id = 37; { send_item_key, SET_MAX_NAME_SIZE },
{ value_out, value_out_size },
Result rc = serviceIpcDispatch(&g_setsysSrv); },
);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 size;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && size_out) *size_out = resp->size;
}
return rc;
} }
Result setsysGetSerialNumber(char *serial) { Result setsysGetSerialNumber(char *serial) {
IpcCommand c; char out[0x18]={0};
ipcInitialize(&c);
if (serial) memset(serial, 0, 0x19); Result rc = serviceDispatchOut(&g_setsysSrv, 68, out);
if (R_SUCCEEDED(rc) && serial) {
struct { memcpy(serial, out, 0x18);
u64 magic; serial[0x18]=0;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 68;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
char serial[0x18];
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && serial)
memcpy(serial, resp->serial, 0x18);
} }
return rc; return rc;
} }
Result setsysGetFlag(SetSysFlag flag, bool *out) { Result setsysGetFlag(SetSysFlag flag, bool *out) {
IpcCommand c; return _setCmdNoInOutBool(&g_setsysSrv, out, flag);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = flag;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u8 flag;
} *resp = r.Raw;
*out = resp->flag;
rc = resp->result;
}
return rc;
} }
Result setsysSetFlag(SetSysFlag flag, bool enable) { Result setsysSetFlag(SetSysFlag flag, bool enable) {
IpcCommand c; return _setCmdInBoolNoOut(&g_setsysSrv, enable, flag + 1);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 flag;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = flag + 1;
raw->flag = enable;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u8 flag;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
static Result _setsysGetFirmwareVersionImpl(SetSysFirmwareVersion *out, u32 cmd_id) { static Result _setsysGetFirmwareVersionImpl(SetSysFirmwareVersion *out, u32 cmd_id) {
IpcCommand c; return serviceDispatch(&g_setsysSrv, cmd_id,
ipcInitialize(&c); .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
ipcAddRecvStatic(&c, out, sizeof(*out), 0); .buffers = { { out, sizeof(*out) } },
);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_setsysSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_setsysSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out) { Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out) {
@ -622,143 +276,35 @@ Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out) {
} }
} }
Result setsysBindFatalDirtyFlagEvent(Event *out) { Result setsysBindFatalDirtyFlagEvent(Event *out_event) {
IpcCommand c; return _setCmdGetEvent(&g_setsysSrv, out_event, false, 93);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 93;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
eventLoadRemote(out, r.Handles[0], false);
}
}
return rc;
} }
Result setsysGetFatalDirtyFlags(u64 *flags_0, u64 *flags_1) { Result setsysGetFatalDirtyFlags(u64 *flags_0, u64 *flags_1) {
IpcCommand c;
ipcInitialize(&c);
struct { struct {
u64 magic; u64 flags_0;
u64 cmd_id; u64 flags_1;
} *raw; } out;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 94;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 flags_0;
u64 flags_1;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*flags_0 = resp->flags_0;
*flags_1 = resp->flags_1;
}
}
Result rc = serviceDispatchOut(&g_setsysSrv, 94, out);
if (R_SUCCEEDED(rc) && flags_0) *flags_0 = out.flags_0;
if (R_SUCCEEDED(rc) && flags_1) *flags_1 = out.flags_1;
return rc; return rc;
} }
Result setsysGetDeviceNickname(char* nickname) { Result setsysGetDeviceNickname(char* nickname) {
IpcCommand c; return serviceDispatch(&g_setsysSrv, 77,
ipcInitialize(&c); .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { nickname, SET_MAX_NICKNAME_SIZE } },
ipcAddRecvBuffer(&c, nickname, SET_MAX_NICKNAME_SIZE, BufferType_Normal); );
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 77;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result setsysSetDeviceNickname(const char* nickname) { Result setsysSetDeviceNickname(const char* nickname) {
char send_nickname[SET_MAX_NICKNAME_SIZE] = {0}; char send_nickname[SET_MAX_NICKNAME_SIZE] = {0};
strncpy(send_nickname, nickname, SET_MAX_NICKNAME_SIZE-1); strncpy(send_nickname, nickname, SET_MAX_NICKNAME_SIZE-1);
IpcCommand c; return serviceDispatch(&g_setsysSrv, 78,
ipcInitialize(&c); .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
ipcAddSendBuffer(&c, send_nickname, SET_MAX_NICKNAME_SIZE, 0); .buffers = { { send_nickname, SET_MAX_NICKNAME_SIZE } },
);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 78;
Result rc = serviceIpcDispatch(&g_setsysSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }

View File

@ -1,13 +1,9 @@
// Copyright 2017 plutoo // Copyright 2017 plutoo
#include "types.h" #define NX_SERVICE_ASSUME_NON_DOMAIN
#include "result.h" #include "service_guard.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "services/fatal.h" #include "services/fatal.h"
#include "services/sm.h"
static Service g_smSrv; static Service g_smSrv;
static u64 g_refCnt;
#define MAX_OVERRIDES 32 #define MAX_OVERRIDES 32
@ -33,28 +29,17 @@ void smAddOverrideHandle(u64 name, Handle handle)
Handle smGetServiceOverride(u64 name) Handle smGetServiceOverride(u64 name)
{ {
size_t i; for (size_t i = 0; i < g_smOverridesNum; i++)
for (i=0; i<g_smOverridesNum; i++)
{
if (g_smOverrides[i].name == name) if (g_smOverrides[i].name == name)
return g_smOverrides[i].handle; return g_smOverrides[i].handle;
}
return INVALID_HANDLE; return INVALID_HANDLE;
} }
bool smHasInitialized(void) { NX_GENERATE_SERVICE_GUARD(sm);
return serviceIsActive(&g_smSrv);
}
Result smInitialize(void) Result _smInitialize(void)
{ {
atomicIncrement64(&g_refCnt);
if (smHasInitialized())
return 0;
Handle sm_handle; Handle sm_handle;
Result rc = svcConnectToNamedPort(&sm_handle, "sm:"); Result rc = svcConnectToNamedPort(&sm_handle, "sm:");
while (R_VALUE(rc) == KERNELRESULT(NotFound)) { while (R_VALUE(rc) == KERNELRESULT(NotFound)) {
@ -68,51 +53,19 @@ Result smInitialize(void)
Handle tmp; Handle tmp;
if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, smEncodeName("")) == 0x415) { if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, smEncodeName("")) == 0x415) {
IpcCommand c; const struct {
ipcInitialize(&c); u64 pid_placeholder;
ipcSendPid(&c); } in = { 0 };
struct { rc = serviceDispatchIn(&g_smSrv, 0, in, .in_send_pid = true);
u64 magic;
u64 cmd_id;
u64 zero;
u64 reserved[2];
} *raw;
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->zero = 0;
rc = serviceIpcDispatch(&g_smSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
} }
if (R_FAILED(rc))
smExit();
return rc; return rc;
} }
void smExit(void) void _smCleanup(void)
{ {
if (atomicDecrement64(&g_refCnt) == 0) serviceClose(&g_smSrv);
{
serviceClose(&g_smSrv);
}
} }
Service *smGetServiceSession(void) Service *smGetServiceSession(void)
@ -120,43 +73,21 @@ Service *smGetServiceSession(void)
return &g_smSrv; return &g_smSrv;
} }
u64 smEncodeName(const char* name)
{
u64 name_encoded = 0;
size_t i;
for (i=0; i<8; i++)
{
if (name[i] == '\0')
break;
name_encoded |= ((u64) name[i]) << (8*i);
}
return name_encoded;
}
Result smGetService(Service* service_out, const char* name) Result smGetService(Service* service_out, const char* name)
{ {
u64 name_encoded = smEncodeName(name); u64 name_encoded = smEncodeName(name);
Handle handle = smGetServiceOverride(name_encoded); Handle handle = smGetServiceOverride(name_encoded);
Result rc; bool own_handle = false;
Result rc = 0;
if (handle != INVALID_HANDLE) if (handle == INVALID_HANDLE) {
{ own_handle = true;
service_out->type = ServiceType_Override;
service_out->handle = handle;
rc = 0;
}
else
{
rc = smGetServiceOriginal(&handle, name_encoded); rc = smGetServiceOriginal(&handle, name_encoded);
}
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc)) {
{ serviceCreate(service_out, handle);
service_out->type = ServiceType_Normal; service_out->own_handle = own_handle;
service_out->handle = handle;
}
} }
return rc; return rc;
@ -164,117 +95,35 @@ Result smGetService(Service* service_out, const char* name)
Result smGetServiceOriginal(Handle* handle_out, u64 name) Result smGetServiceOriginal(Handle* handle_out, u64 name)
{ {
IpcCommand c; const struct {
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 service_name; u64 service_name;
u64 reserved[2]; } in = { name };
} *raw;
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw)); return serviceDispatchIn(&g_smSrv, 1, in,
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
raw->magic = SFCI_MAGIC; .out_handles = handle_out,
raw->cmd_id = 1; );
raw->service_name = name;
Result rc = serviceIpcDispatch(&g_smSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*handle_out = r.Handles[0];
}
}
return rc;
} }
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions) { Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions)
IpcCommand c; {
ipcInitialize(&c); const struct {
struct {
u64 magic;
u64 cmd_id;
u64 service_name; u64 service_name;
u32 is_light; u32 is_light;
u32 max_sessions; u32 max_sessions;
} *raw; } in = { smEncodeName(name), !!is_light, max_sessions };
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw)); return serviceDispatchIn(&g_smSrv, 2, in,
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
raw->magic = SFCI_MAGIC; .out_handles = handle_out,
raw->cmd_id = 2; );
raw->service_name = smEncodeName(name);
raw->is_light = !!is_light;
raw->max_sessions = max_sessions;
Result rc = serviceIpcDispatch(&g_smSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*handle_out = r.Handles[0];
}
}
return rc;
} }
Result smUnregisterService(const char* name) { Result smUnregisterService(const char* name)
IpcCommand c; {
ipcInitialize(&c); const struct {
struct {
u64 magic;
u64 cmd_id;
u64 service_name; u64 service_name;
u64 reserved; } in = { smEncodeName(name) };
} *raw;
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw)); return serviceDispatchIn(&g_smSrv, 3, in);
raw->magic = SFCI_MAGIC;
raw->cmd_id = 3;
raw->service_name = smEncodeName(name);
Result rc = serviceIpcDispatch(&g_smSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,19 @@
#include <string.h> #define NX_SERVICE_ASSUME_NON_DOMAIN
#include "types.h" #include "service_guard.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "services/time.h" #include "services/time.h"
#include "services/sm.h"
static Service g_timeSrv; static Service g_timeSrv;
static Service g_timeUserSystemClock; static Service g_timeUserSystemClock;
static Service g_timeNetworkSystemClock; static Service g_timeNetworkSystemClock;
static Service g_timeTimeZoneService; static Service g_timeTimeZoneService;
static Service g_timeLocalSystemClock; static Service g_timeLocalSystemClock;
static u64 g_refCnt;
static Result _timeGetSession(Service* srv_out, u64 cmd_id); static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id);
Result timeInitialize(void) NX_GENERATE_SERVICE_GUARD(time);
{
atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_timeSrv)) Result _timeInitialize(void) {
return 0; Result rc=0;
Result rc;
rc = smGetService(&g_timeSrv, "time:s"); rc = smGetService(&g_timeSrv, "time:s");
if (R_FAILED(rc)) if (R_FAILED(rc))
@ -31,75 +22,33 @@ Result timeInitialize(void)
if (R_FAILED(rc)) if (R_FAILED(rc))
return rc; return rc;
rc = _timeGetSession(&g_timeUserSystemClock, 0); rc = _timeCmdGetSession(&g_timeSrv, &g_timeUserSystemClock, 0);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = _timeGetSession(&g_timeNetworkSystemClock, 1); rc = _timeCmdGetSession(&g_timeSrv, &g_timeNetworkSystemClock, 1);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = _timeGetSession(&g_timeTimeZoneService, 3); rc = _timeCmdGetSession(&g_timeSrv, &g_timeTimeZoneService, 3);
if (R_SUCCEEDED(rc)) if (R_SUCCEEDED(rc))
rc = _timeGetSession(&g_timeLocalSystemClock, 4); rc = _timeCmdGetSession(&g_timeSrv, &g_timeLocalSystemClock, 4);
if (R_FAILED(rc))
timeExit();
return rc; return rc;
} }
void timeExit(void) void _timeCleanup(void) {
{ serviceClose(&g_timeLocalSystemClock);
if (atomicDecrement64(&g_refCnt) == 0) serviceClose(&g_timeTimeZoneService);
{ serviceClose(&g_timeNetworkSystemClock);
serviceClose(&g_timeLocalSystemClock); serviceClose(&g_timeUserSystemClock);
serviceClose(&g_timeTimeZoneService); serviceClose(&g_timeSrv);
serviceClose(&g_timeNetworkSystemClock);
serviceClose(&g_timeUserSystemClock);
serviceClose(&g_timeSrv);
}
} }
Service* timeGetServiceSession(void) { Service* timeGetServiceSession(void) {
return &g_timeSrv; return &g_timeSrv;
} }
static Result _timeGetSession(Service* srv_out, u64 cmd_id) { Service* timeGetServiceSession_SystemClock(TimeType type) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(&g_timeSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(srv_out, r.Handles[0]);
}
}
return rc;
}
static Service* _timeGetClockSession(TimeType type) {
if (type==TimeType_UserSystemClock) { if (type==TimeType_UserSystemClock) {
return &g_timeUserSystemClock; return &g_timeUserSystemClock;
} }
@ -114,403 +63,143 @@ static Service* _timeGetClockSession(TimeType type) {
} }
} }
Service* timeGetServiceSession_TimeZoneService(void) {
return &g_timeTimeZoneService;
}
static Result _timeCmdGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
return serviceDispatch(srv, cmd_id,
.out_num_objects = 1,
.out_objects = srv_out,
);
}
static Result _timeCmdInU64NoOut(Service* srv, u64 inval, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, inval);
}
static Result _timeCmdNoInOutU64(Service* srv, u64 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _appletCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
Result timeGetCurrentTime(TimeType type, u64 *timestamp) { Result timeGetCurrentTime(TimeType type, u64 *timestamp) {
Service *srv = _timeGetClockSession(type); Service *srv = timeGetServiceSession_SystemClock(type);
if (srv==NULL) if (srv==NULL)
return MAKERESULT(Module_Libnx, LibnxError_BadInput); return MAKERESULT(Module_Libnx, LibnxError_BadInput);
IpcCommand c; return _timeCmdNoInOutU64(srv, timestamp, 0);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 timestamp;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && timestamp) *timestamp = resp->timestamp;
}
return rc;
} }
Result timeSetCurrentTime(TimeType type, u64 timestamp) { Result timeSetCurrentTime(TimeType type, u64 timestamp) {
Service *srv = _timeGetClockSession(type); Service *srv = timeGetServiceSession_SystemClock(type);
if (srv==NULL) if (srv==NULL)
return MAKERESULT(Module_Libnx, LibnxError_BadInput); return MAKERESULT(Module_Libnx, LibnxError_BadInput);
IpcCommand c; return _timeCmdInU64NoOut(srv, timestamp, 1);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 timestamp;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
raw->timestamp = timestamp;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result timeGetDeviceLocationName(TimeLocationName *name) { Result timeGetDeviceLocationName(TimeLocationName *name) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
struct { return serviceDispatchOut(&g_timeTimeZoneService, 0, *name);
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
TimeLocationName name;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && name) memcpy(name, &resp->name, sizeof(TimeLocationName));
}
return rc;
} }
Result timeSetDeviceLocationName(const TimeLocationName *name) { Result timeSetDeviceLocationName(const TimeLocationName *name) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
struct { return serviceDispatchIn(&g_timeTimeZoneService, 1, *name);
u64 magic;
u64 cmd_id;
TimeLocationName name;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
memcpy(&raw->name, name, sizeof(TimeLocationName));
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result timeGetTotalLocationNameCount(u32 *total_location_name_count) { Result timeGetTotalLocationNameCount(s32 *total_location_name_count) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
struct { return _appletCmdNoInOutU32(&g_timeTimeZoneService, (u32*)total_location_name_count, 2);
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2;
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 total_location_name_count;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && total_location_name_count) *total_location_name_count = resp->total_location_name_count;
}
return rc;
} }
Result timeLoadLocationNameList(u32 index, TimeLocationName *location_name_array, size_t location_name_size, u32 *location_name_count) { Result timeLoadLocationNameList(s32 index, TimeLocationName *location_name_array, s32 location_name_max, s32 *location_name_count) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
ipcAddRecvBuffer(&c, location_name_array, location_name_size, BufferType_Normal);
struct { return serviceDispatchInOut(&g_timeTimeZoneService, 3, index, *location_name_count,
u64 magic; .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
u64 cmd_id; .buffers = { { location_name_array, sizeof(TimeLocationName)*location_name_max } },
u32 index; );
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 3;
raw->index = index;
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 location_name_count;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && location_name_count) *location_name_count = resp->location_name_count;
}
return rc;
} }
Result timeLoadTimeZoneRule(const TimeLocationName *name, TimeZoneRule *rule) { Result timeLoadTimeZoneRule(const TimeLocationName *name, TimeZoneRule *rule) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
ipcAddRecvBuffer(&c, rule, sizeof(TimeZoneRule), BufferType_Normal);
struct { return serviceDispatchIn(&g_timeTimeZoneService, 4, *name,
u64 magic; .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
u64 cmd_id; .buffers = { { rule, sizeof(TimeZoneRule) } },
TimeLocationName name; );
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 4;
memcpy(&raw->name, name, sizeof(TimeLocationName));
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} }
Result timeToCalendarTime(const TimeZoneRule *rule, u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info) { Result timeToCalendarTime(const TimeZoneRule *rule, u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
ipcAddSendBuffer(&c, rule, sizeof(TimeZoneRule), BufferType_Normal);
struct { struct {
u64 magic; TimeCalendarTime caltime;
u64 cmd_id; TimeCalendarAdditionalInfo info;
u64 timestamp; } out;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 100;
raw->timestamp = timestamp;
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
TimeCalendarTime caltime;
TimeCalendarAdditionalInfo info;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && caltime) memcpy(caltime, &resp->caltime, sizeof(TimeCalendarTime));
if (R_SUCCEEDED(rc) && info) memcpy(info, &resp->info, sizeof(TimeCalendarAdditionalInfo));
}
Result rc = serviceDispatchInOut(&g_timeTimeZoneService, 100, timestamp, out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { rule, sizeof(TimeZoneRule) } },
);
if (R_SUCCEEDED(rc) && caltime) *caltime = out.caltime;
if (R_SUCCEEDED(rc) && info) *info = out.info;
return rc; return rc;
} }
Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info) { Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
struct { struct {
u64 magic;
u64 cmd_id;
u64 timestamp;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 101;
raw->timestamp = timestamp;
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
TimeCalendarTime caltime;
TimeCalendarAdditionalInfo info;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && caltime) memcpy(caltime, &resp->caltime, sizeof(TimeCalendarTime));
if (R_SUCCEEDED(rc) && info) memcpy(info, &resp->info, sizeof(TimeCalendarAdditionalInfo));
}
return rc;
}
Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count) {
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, rule, sizeof(TimeZoneRule), BufferType_Normal);
ipcAddRecvStatic(&c, timestamp_list, timestamp_list_size, 0);
struct {
u64 magic;
u64 cmd_id;
TimeCalendarTime caltime; TimeCalendarTime caltime;
} *raw; TimeCalendarAdditionalInfo info;
} out;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 201;
raw->caltime = *caltime;
Result rc = serviceIpcDispatch(&g_timeTimeZoneService);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 timestamp_count;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && timestamp_count) *timestamp_count = resp->timestamp_count;
}
Result rc = serviceDispatchInOut(&g_timeTimeZoneService, 101, timestamp, out);
if (R_SUCCEEDED(rc) && caltime) *caltime = out.caltime;
if (R_SUCCEEDED(rc) && info) *info = out.info;
return rc; return rc;
} }
Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, size_t timestamp_list_size, u32 *timestamp_count) { Result timeToPosixTime(const TimeZoneRule *rule, const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count) {
IpcCommand c; if (!serviceIsActive(&g_timeTimeZoneService))
ipcInitialize(&c); return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
ipcAddRecvStatic(&c, timestamp_list, timestamp_list_size, 0);
struct { return serviceDispatchInOut(&g_timeTimeZoneService, 201, *caltime, *timestamp_count,
u64 magic; .buffer_attrs = {
u64 cmd_id; SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
TimeCalendarTime caltime; SfBufferAttr_HipcPointer | SfBufferAttr_Out,
} *raw; },
.buffers = {
raw = ipcPrepareHeader(&c, sizeof(*raw)); { rule, sizeof(TimeZoneRule) },
{ timestamp_list, sizeof(u64)*timestamp_list_count },
raw->magic = SFCI_MAGIC; },
raw->cmd_id = 202; );
raw->caltime = *caltime; }
Result rc = serviceIpcDispatch(&g_timeTimeZoneService); Result timeToPosixTimeWithMyRule(const TimeCalendarTime *caltime, u64 *timestamp_list, s32 timestamp_list_count, s32 *timestamp_count) {
if (!serviceIsActive(&g_timeTimeZoneService))
if (R_SUCCEEDED(rc)) { return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
IpcParsedCommand r;
ipcParse(&r); return serviceDispatchInOut(&g_timeTimeZoneService, 202, *caltime, *timestamp_count,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out },
struct { .buffers = { { timestamp_list, sizeof(u64)*timestamp_list_count } },
u64 magic; );
u64 result;
u32 timestamp_count;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && timestamp_count) *timestamp_count = resp->timestamp_count;
}
return rc;
} }

48
nx/source/services/ts.c Normal file
View File

@ -0,0 +1,48 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h>
#include "service_guard.h"
#include "runtime/hosversion.h"
#include "services/ts.h"
static Service g_tsSrv;
NX_GENERATE_SERVICE_GUARD(ts);
Result _tsInitialize(void) {
return smGetService(&g_tsSrv, "ts");
}
void _tsCleanup(void) {
serviceClose(&g_tsSrv);
}
Service* tsGetServiceSession(void) {
return &g_tsSrv;
}
static Result _tsCmdInU8Out32(u8 inval, u32 *out, u64 cmd_id) {
return serviceDispatchInOut(&g_tsSrv, cmd_id, inval, *out);
}
Result tsGetTemperatureRange(TsLocation location, s32 *min_temperature, s32 *max_temperature) {
u8 tmp_location = location;
struct {
s32 min_temperature;
s32 max_temperature;
} out;
Result rc = serviceDispatchInOut(&g_tsSrv, 0, tmp_location, out);
if (R_SUCCEEDED(rc) && min_temperature) *min_temperature = out.min_temperature;
if (R_SUCCEEDED(rc) && max_temperature) *max_temperature = out.max_temperature;
return rc;
}
Result tsGetTemperature(TsLocation location, s32 *temperature) {
return _tsCmdInU8Out32(location, (u32*)temperature, 1);
}
Result tsGetTemperatureMilliC(TsLocation location, s32 *temperature) {
return _tsCmdInU8Out32(location, (u32*)temperature, 3);
}

View File

@ -725,8 +725,6 @@ Result usbHsIfOpenUsbEp(UsbHsClientIfSession* s, UsbHsClientEpSession* ep, u16 m
if (R_SUCCEEDED(rc)) rc = _usbHsGetEvent(&ep->s, &ep->eventXfer, 2); if (R_SUCCEEDED(rc)) rc = _usbHsGetEvent(&ep->s, &ep->eventXfer, 2);
} }
if (hosversionAtLeast(3,0,0) && R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(ep->s.handle, &ep->ptrbufsize);
if (R_FAILED(rc)) { if (R_FAILED(rc)) {
serviceClose(&ep->s); serviceClose(&ep->s);
eventClose(&ep->eventXfer); eventClose(&ep->eventXfer);
@ -854,7 +852,7 @@ static Result _usbHsEpGetXferReport(UsbHsClientEpSession* s, UsbHsXferReport* re
ipcAddRecvBuffer(&c, reports, sizeof(UsbHsXferReport) * max_reports, BufferType_Normal); ipcAddRecvBuffer(&c, reports, sizeof(UsbHsXferReport) * max_reports, BufferType_Normal);
} }
else { else {
ipcAddRecvSmart(&c, s->ptrbufsize, reports, sizeof(UsbHsXferReport) * max_reports, 0); ipcAddRecvSmart(&c, s->s.pointer_buffer_size, reports, sizeof(UsbHsXferReport) * max_reports, 0);
} }
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw)); raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));

View File

@ -1,111 +1,34 @@
/** #define NX_SERVICE_ASSUME_NON_DOMAIN
* @file wlaninf.c #include "service_guard.h"
* @brief WLAN InfraManager service IPC wrapper.
* @author natinusala
* @copyright libnx Authors
*/
#include "types.h"
#include "result.h"
#include "services/sm.h"
#include "services/wlaninf.h" #include "services/wlaninf.h"
#include "arm/atomics.h"
static Service g_wlaninfSrv; static Service g_wlaninfSrv;
static u64 g_refCnt;
Result wlaninfInitialize(void) { NX_GENERATE_SERVICE_GUARD(wlaninf);
Result rc;
atomicIncrement64(&g_refCnt); Result _wlaninfInitialize(void) {
return smGetService(&g_wlaninfSrv, "wlan:inf");
if (serviceIsActive(&g_wlaninfSrv))
return 0;
rc = smGetService(&g_wlaninfSrv, "wlan:inf");
if (R_FAILED(rc))
wlaninfExit();
return rc;
} }
void wlaninfExit(void) { void _wlaninfCleanup(void) {
if (atomicDecrement64(&g_refCnt) == 0) { serviceClose(&g_wlaninfSrv);
serviceClose(&g_wlaninfSrv);
}
} }
Service* wlaninfGetServiceSession(void) { Service* wlaninfGetServiceSession(void) {
return &g_wlaninfSrv; return &g_wlaninfSrv;
} }
static Result _wlaninfCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
Result wlaninfGetState(WlanInfState* out) { Result wlaninfGetState(WlanInfState* out) {
IpcCommand c; u32 tmp=0;
ipcInitialize(&c); Result rc = _wlaninfCmdNoInOutU32(&g_wlaninfSrv, &tmp, 10);
if (R_SUCCEEDED(rc) && out) *out = tmp;
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_wlaninfSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 10;
Result rc = serviceIpcDispatch(&g_wlaninfSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 out;
} *resp;
serviceIpcParse(&g_wlaninfSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
*out = resp->out;
}
return rc; return rc;
} }
Result wlaninfGetRSSI(s32* out) { Result wlaninfGetRSSI(s32* out) {
IpcCommand c; return _wlaninfCmdNoInOutU32(&g_wlaninfSrv, (u32*)out, 12);
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_wlaninfSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 12;
Result rc = serviceIpcDispatch(&g_wlaninfSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
s32 out;
} *resp;
serviceIpcParse(&g_wlaninfSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
*out = resp->out;
}
return rc;
} }