mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
Added support for tmem with AppletStorage, and added HandleStorage support. applet IPC improvements.
This commit is contained in:
parent
f5682b267e
commit
d65c2ec94b
@ -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.
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user