Added support for tmem with AppletStorage, and added HandleStorage support. applet IPC improvements.

This commit is contained in:
yellows8 2018-12-15 16:34:23 -05:00
parent f5682b267e
commit d65c2ec94b
2 changed files with 270 additions and 38 deletions

View File

@ -7,6 +7,7 @@
#pragma once
#include "../types.h"
#include "../services/sm.h"
#include "../kernel/tmem.h"
typedef enum {
AppletType_None = -2,
@ -64,6 +65,8 @@ struct AppletHookCookie
/// applet IStorage
typedef struct {
Service s;
TransferMemory tmem;
bool isHandleStorage;
} AppletStorage;
Result appletInitialize(void);
@ -123,14 +126,41 @@ Result appletSetScreenShotImageOrientation(s32 val);
*/
Result appletCreateStorage(AppletStorage *s, s64 size);
/// Closes the storage object.
/**
* @brief Creates a TransferMemory storage.
* @param s Storage object.
* @param size Size of storage.
* @param writable Controls whether writing to the storage is allowed with \ref appletStorageWrite.
*/
Result appletCreateTransferMemoryStorage(AppletStorage *s, s64 size, bool writable);
/**
* @brief Creates a HandleStorage. Only available on 2.0.0+.
* @param s Storage object.
* @param inval Arbitrary input value.
* @param handle Arbitrary input handle.
*/
Result appletCreateHandleStorage(AppletStorage *s, s64 inval, Handle handle);
/**
* @brief Creates a HandleStorage using TransferMemory. Wrapper for \ref appletCreateHandleStorage.
* @param s Storage object.
* @param size Size of storage.
*/
Result appletCreateHandleStorageTmem(AppletStorage *s, s64 size);
/// Closes the storage object. TransferMemory closing is seperate, see \ref appletStorageCloseTmem.
void appletStorageClose(AppletStorage *s);
/// Gets the size of the storage.
/// Closes the TransferMemory in the storage object. For TransferMemory storage created by the current process, this must be called after the LibraryApplet finishes using it (if sent to one).
void appletStorageCloseTmem(AppletStorage *s);
/// Gets the size of the storage. For HandleStorage, this returns the input s64 originally from /ref appletCreateHandleStorage / \ref appletCreateHandleStorageTmem.
Result appletStorageGetSize(AppletStorage *s, s64 *size);
/**
* @brief Writes to a storage. offset(+size) must be within the actual storage size.
* @note This is not usable with HandleStorage.
* @param s Storage object.
* @param offset Offset in storage.
* @param buffer Input data.
@ -140,6 +170,7 @@ Result appletStorageWrite(AppletStorage *s, s64 offset, const void* buffer, size
/**
* @brief Reads from a storage. offset(+size) must be within the actual storage size.
* @note This is not usable with HandleStorage.
* @param s Storage object.
* @param offset Offset in storage.
* @param buffer Input data.
@ -147,6 +178,23 @@ Result appletStorageWrite(AppletStorage *s, s64 offset, const void* buffer, size
*/
Result appletStorageRead(AppletStorage *s, s64 offset, void* buffer, size_t size);
/**
* @brief Gets data for a HandleStorage originally from \ref appletCreateHandleStorage input.
* @note Only available on 2.0.0+.
* @param out Same as \ref appletStorageGetSize.
* @param handle Output handle.
*/
Result appletStorageGetHandle(AppletStorage *s, s64 *out, Handle *handle);
/**
* @brief Maps TransferMemory for a HandleStorage. Wrapper for \ref appletCreateHandleStorage.
* @note The TransferMemory can be unmapped with \ref appletStorageCloseTmem.
* @param s Storage object.
* @param addr Output mapped address (optional).
* @param size Output size (optional).
*/
Result appletStorageMap(AppletStorage *s, void** addr, size_t *size);
/**
* @brief Processes the current applet status. Generally used within a main loop.
* @return Whether the application should continue running.

View File

@ -655,6 +655,50 @@ static Result _appletCmdNoInOut64(Service* srv, u64 *out, u64 cmd_id) {
return rc;
}
static Result _appletCmdInHandle64(Service* srv, Service* srv_out, u64 cmd_id, Handle handle, u64 inval) {
IpcCommand c;
ipcInitialize(&c);
ipcSendHandleCopy(&c, handle);
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) && srv_out) {
serviceCreateSubservice(srv_out, srv, &r, 0);
}
}
return rc;
}
static Result _appletCmdInTmem(Service* srv, Service* srv_out, u64 cmd_id, TransferMemory *tmem) {
return _appletCmdInHandle64(srv, srv_out, cmd_id, tmem->handle, tmem->size);
}
// IWindowController
static Result _appletGetAppletResourceUserId(u64 *out) {
@ -809,45 +853,13 @@ Result appletIsGamePlayRecordingSupported(bool *flag) {
}
static Result _appletInitializeGamePlayRecording(TransferMemory *tmem) {
IpcCommand c;
ipcInitialize(&c);
if (!serviceIsActive(&g_appletSrv) || !_appletIsRegularApplication())
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (!kernelAbove300())
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
ipcSendHandleCopy(&c, tmem->handle);
struct {
u64 magic;
u64 cmd_id;
u64 size;
} *raw;
raw = serviceIpcPrepareHeader(&g_appletIFunctions, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 66;
raw->size = tmem->size;
Result rc = serviceIpcDispatch(&g_appletIFunctions);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_appletIFunctions, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
return _appletCmdInTmem(&g_appletIFunctions, NULL, 66, tmem);
}
Result appletSetGamePlayRecordingState(bool state) {
@ -1340,13 +1352,101 @@ static Result _appletExitProcessAndReturn(void) {
// ILibraryAppletCreator
Result appletCreateStorage(AppletStorage *s, s64 size) {
memset(s, 0, sizeof(AppletStorage));
s->isHandleStorage = false;
return _appletGetSessionIn64(&g_appletILibraryAppletCreator, &s->s, 10, size);
}
static Result _appletCreateTransferMemoryStorage(Service* srv_out, TransferMemory *tmem, bool writable) {
IpcCommand c;
ipcInitialize(&c);
ipcSendHandleCopy(&c, tmem->handle);
struct {
u64 magic;
u64 cmd_id;
u8 writable;
u64 size;
} *raw;
raw = serviceIpcPrepareHeader(&g_appletILibraryAppletCreator, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 11;
raw->writable = writable!=0;
raw->size = tmem->size;
Result rc = serviceIpcDispatch(&g_appletILibraryAppletCreator);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_appletILibraryAppletCreator, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && srv_out) {
serviceCreateSubservice(srv_out, &g_appletILibraryAppletCreator, &r, 0);
}
}
return rc;
}
Result appletCreateTransferMemoryStorage(AppletStorage *s, s64 size, bool writable) {
Result rc=0;
memset(s, 0, sizeof(AppletStorage));
s->isHandleStorage = false;
rc = tmemCreate(&s->tmem, size, Perm_None);
if (R_FAILED(rc)) return rc;
rc = _appletCreateTransferMemoryStorage(&s->s, &s->tmem, writable);
if (R_FAILED(rc)) tmemClose(&s->tmem);
return rc;
}
Result appletCreateHandleStorage(AppletStorage *s, s64 inval, Handle handle) {
if (!kernelAbove200())
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
s->isHandleStorage = true;
return _appletCmdInHandle64(&g_appletILibraryAppletCreator, &s->s, 12, handle, inval);
}
Result appletCreateHandleStorageTmem(AppletStorage *s, s64 size) {
Result rc=0;
memset(s, 0, sizeof(AppletStorage));
s->isHandleStorage = true;
rc = tmemCreate(&s->tmem, size, Perm_None);
if (R_FAILED(rc)) return rc;
rc = appletCreateHandleStorage(s, s->tmem.size, s->tmem.handle);
if (R_FAILED(rc)) tmemClose(&s->tmem);
return rc;
}
void appletStorageClose(AppletStorage *s) {
serviceClose(&s->s);
}
void appletStorageCloseTmem(AppletStorage *s) {
tmemClose(&s->tmem);
}
static Result _appletStorageAccessorRW(Service* srv, size_t ipcbufsize, s64 offset, void* buffer, size_t size, bool rw) {
IpcCommand c;
ipcInitialize(&c);
@ -1386,12 +1486,19 @@ static Result _appletStorageAccessorRW(Service* srv, size_t ipcbufsize, s64 offs
Result appletStorageGetSize(AppletStorage *s, s64 *size) {
Result rc=0;
Service tmp_srv;//IStorageAccessor
Service tmp_srv;//IStorageAccessor / ITransferStorageAccessor
if (!serviceIsActive(&s->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
rc = _appletGetSession(&s->s, &tmp_srv, 0);//Open
if (!s->isHandleStorage) rc = _appletGetSession(&s->s, &tmp_srv, 0);//Open
if (s->isHandleStorage) {
if (!kernelAbove200())
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
rc = _appletGetSession(&s->s, &tmp_srv, 1);//OpenTransferStorage
}
if (R_FAILED(rc)) return rc;
rc = _appletCmdNoInOut64(&tmp_srv, (u64*)size, 0);
@ -1405,7 +1512,7 @@ static Result _appletStorageRW(AppletStorage *s, s64 offset, void* buffer, size_
size_t ipcbufsize=0;
Service tmp_srv;//IStorageAccessor
if (!serviceIsActive(&s->s))
if (!serviceIsActive(&s->s) || s->isHandleStorage)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
rc = _appletGetSession(&s->s, &tmp_srv, 0);//Open
@ -1427,6 +1534,83 @@ Result appletStorageRead(AppletStorage *s, s64 offset, void* buffer, size_t size
return _appletStorageRW(s, offset, buffer, size, false);
}
static Result _appletStorageGetHandle(Service* srv, s64 *out, Handle *handle) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
Result rc = serviceIpcDispatch(srv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
s64 out;
} *resp;
serviceIpcParse(srv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (out) *out = resp->out;
if (handle) *handle = r.Handles[0];
}
}
return rc;
}
Result appletStorageGetHandle(AppletStorage *s, s64 *out, Handle *handle) {
Result rc=0;
Service tmp_srv;//ITransferStorageAccessor
if (!serviceIsActive(&s->s) || !s->isHandleStorage)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (!kernelAbove200())
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
rc = _appletGetSession(&s->s, &tmp_srv, 1);//OpenTransferStorage
if (R_FAILED(rc)) return rc;
rc = _appletStorageGetHandle(&tmp_srv, out, handle);
serviceClose(&tmp_srv);
return rc;
}
Result appletStorageMap(AppletStorage *s, void** addr, size_t *size) {
Result rc=0;
s64 tmpsize=0;
Handle tmphandle=0;
rc = appletStorageGetHandle(s, &tmpsize, &tmphandle);
if (R_FAILED(rc)) return rc;
tmemLoadRemote(&s->tmem, tmphandle, tmpsize, Perm_None);
rc = tmemMap(&s->tmem);
if (R_FAILED(rc)) tmemClose(&s->tmem);
if (R_SUCCEEDED(rc)) {
if (addr) *addr = s->tmem.map_addr;
if (size) *size = s->tmem.size;
}
return rc;
}
// state / other
u8 appletGetOperationMode(void) {