diff --git a/nx/include/switch.h b/nx/include/switch.h index f9fef872..398eb0ff 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -13,6 +13,7 @@ extern "C" { #include "switch/result.h" #include "switch/nro.h" +#include "switch/nacp.h" #include "switch/arm/tls.h" #include "switch/arm/cache.h" @@ -45,6 +46,7 @@ extern "C" { #include "switch/services/irs.h" #include "switch/services/vi.h" #include "switch/services/nv.h" +#include "switch/services/ns.h" #include "switch/services/pm.h" #include "switch/services/set.h" diff --git a/nx/include/switch/nacp.h b/nx/include/switch/nacp.h new file mode 100644 index 00000000..e4dc019b --- /dev/null +++ b/nx/include/switch/nacp.h @@ -0,0 +1,48 @@ +/** + * @file nro.h + * @brief Control.nacp structure. + * @copyright libnx Authors + */ + +#pragma once + +/// Language entry. These strings are UTF-8. +typedef struct { + char name[0x200]; + char author[0x100]; +} NacpLanguageEntry; + +typedef struct { + NacpLanguageEntry lang[16]; + + u8 x3000_unk[0x24];////Normally all-zero? + u32 x3024_unk; + u32 x3028_unk; + u32 x302C_unk; + u32 x3030_unk; + u32 x3034_unk; + u64 titleID0; + + u8 x3040_unk[0x20]; + char version[0x10]; + + u64 titleID_DlcBase; + u64 titleID1; + + u32 x3080_unk; + u32 x3084_unk; + u32 x3088_unk; + u8 x308C_unk[0x24];//zeros? + + u64 titleID2; + u64 titleIDs[7];//"Array of application titleIDs, normally the same as the above app-titleIDs. Only set for game-updates?" + + u32 x30F0_unk; + u32 x30F4_unk; + + u64 titleID3;//"Application titleID. Only set for game-updates?" + + char bcatPassphrase[0x40]; + u8 x3140_unk[0xEC0];//Normally all-zero? +} NacpStruct; + diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h new file mode 100644 index 00000000..ae2d556a --- /dev/null +++ b/nx/include/switch/services/ns.h @@ -0,0 +1,19 @@ +/** + * @file ns.h + * @brief NS service IPC wrapper. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../nacp.h" + +typedef struct { + NacpStruct nacp; + u8 icon[0x20000];//JPEG +} nsApplicationControlData; + +Result nsInitialize(void); +void nsExit(void); + +Result nsGetApplicationControlData(u8 flag, u64 titleID, nsApplicationControlData* buffer, size_t size, size_t* actual_size); diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c new file mode 100644 index 00000000..ea433802 --- /dev/null +++ b/nx/source/services/ns.c @@ -0,0 +1,67 @@ +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "services/sm.h" +#include "services/ns.h" + +//TODO: >=3.0.0 support. + +static Service g_nsSrv; +static u64 g_nsRefCnt; + +Result nsInitialize(void) +{ + atomicIncrement64(&g_nsRefCnt); + + if (serviceIsActive(&g_nsSrv)) + return 0; + + return smGetService(&g_nsSrv, "ns:am");//This will fail on >=3.0.0. +} + +void nsExit(void) +{ + if (atomicDecrement64(&g_nsRefCnt) == 0) { + serviceClose(&g_nsSrv); + } +} + +Result nsGetApplicationControlData(u8 flag, u64 titleID, nsApplicationControlData* buffer, size_t size, size_t* actual_size) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buffer, size, 0); + + struct { + u64 magic; + u64 cmd_id; + u8 flag; + u64 titleID; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 400; + raw->flag = flag; + raw->titleID = titleID; + + Result rc = serviceIpcDispatch(&g_nsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u64 actual_size; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && actual_size) *actual_size = resp->actual_size; + } + + return rc; +}