mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-23 21:32:39 +02:00
Refactor service IPC to support domains.
This commit is contained in:
parent
cde495241c
commit
40e0bf4db7
@ -63,6 +63,13 @@ typedef struct {
|
|||||||
u32 Pad[2];
|
u32 Pad[2];
|
||||||
} DomainMessageHeader;
|
} DomainMessageHeader;
|
||||||
|
|
||||||
|
/// IPC domain response header.
|
||||||
|
typedef struct {
|
||||||
|
u32 NumObjectIds;
|
||||||
|
u32 Pad[3];
|
||||||
|
} DomainResponseHeader;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t NumSend; // A
|
size_t NumSend; // A
|
||||||
size_t NumRecv; // B
|
size_t NumRecv; // B
|
||||||
@ -363,12 +370,16 @@ typedef struct {
|
|||||||
Handle Handles[IPC_MAX_OBJECTS]; ///< Handles.
|
Handle Handles[IPC_MAX_OBJECTS]; ///< Handles.
|
||||||
bool WasHandleCopied[IPC_MAX_OBJECTS]; ///< true if the handle was moved, false if it was copied.
|
bool WasHandleCopied[IPC_MAX_OBJECTS]; ///< true if the handle was moved, false if it was copied.
|
||||||
|
|
||||||
bool IsDomainMessage; ///< true if the the message is a Domain message.
|
bool IsDomainRequest; ///< true if the the message is a Domain message.
|
||||||
DomainMessageType MessageType; ///< Type of the domain message.
|
DomainMessageType InMessageType; ///< Type of the domain message.
|
||||||
u32 MessageLength; ///< Size of rawdata (for domain messages).
|
u32 InMessageLength; ///< Size of rawdata (for domain messages).
|
||||||
u32 ThisObjectId; ///< Object ID to call the command on (for domain messages).
|
u32 InThisObjectId; ///< Object ID to call the command on (for domain messages).
|
||||||
size_t NumObjectIds; ///< Number of object IDs (for domain messages).
|
size_t InNumObjectIds; ///< Number of object IDs (for domain messages).
|
||||||
u32 ObjectIds[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.
|
||||||
|
size_t OutNumObjectIds; ///< Number of object IDs (for domain responses).
|
||||||
|
u32 OutObjectIds[IPC_MAX_OBJECTS]; ///< Object IDs (for domain responses).
|
||||||
|
|
||||||
size_t NumBuffers; ///< Number of buffers in the response.
|
size_t NumBuffers; ///< Number of buffers in the response.
|
||||||
void* Buffers[IPC_MAX_BUFFERS]; ///< Pointers to the buffers.
|
void* Buffers[IPC_MAX_BUFFERS]; ///< Pointers to the buffers.
|
||||||
@ -399,7 +410,8 @@ static inline Result ipcParse(IpcParsedCommand* r) {
|
|||||||
u32 ctrl1 = *buf++;
|
u32 ctrl1 = *buf++;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
r->IsDomainMessage = false;
|
r->IsDomainRequest = false;
|
||||||
|
r->IsDomainResponse = false;
|
||||||
|
|
||||||
r->CommandType = (IpcCommandType) (ctrl0 & 0xffff);
|
r->CommandType = (IpcCommandType) (ctrl0 & 0xffff);
|
||||||
r->HasPid = false;
|
r->HasPid = false;
|
||||||
@ -656,11 +668,11 @@ static inline void* ipcPrepareHeaderForDomain(IpcCommand* cmd, size_t sizeof_raw
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parse an IPC command response into an IPC parsed command structure (domain version).
|
* @brief Parse an IPC command request into an IPC parsed command structure (domain version).
|
||||||
* @param IPC parsed command structure to fill in.
|
* @param IPC parsed command structure to fill in.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
static inline Result ipcParseForDomain(IpcParsedCommand* r) {
|
static inline Result ipcParseDomainRequest(IpcParsedCommand* r) {
|
||||||
Result rc = ipcParse(r);
|
Result rc = ipcParse(r);
|
||||||
DomainMessageHeader *hdr;
|
DomainMessageHeader *hdr;
|
||||||
u32 *object_ids;
|
u32 *object_ids;
|
||||||
@ -671,22 +683,51 @@ static inline Result ipcParseForDomain(IpcParsedCommand* r) {
|
|||||||
object_ids = (u32*)(((uintptr_t) hdr) + sizeof(DomainMessageHeader) + hdr->Length);
|
object_ids = (u32*)(((uintptr_t) hdr) + sizeof(DomainMessageHeader) + hdr->Length);
|
||||||
r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainMessageHeader));
|
r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainMessageHeader));
|
||||||
|
|
||||||
r->IsDomainMessage = true;
|
r->IsDomainRequest = true;
|
||||||
r->MessageType = (DomainMessageType)(hdr->Type);
|
r->InMessageType = (DomainMessageType)(hdr->Type);
|
||||||
switch (r->MessageType) {
|
switch (r->InMessageType) {
|
||||||
case DomainMessageType_SendMessage:
|
case DomainMessageType_SendMessage:
|
||||||
case DomainMessageType_Close:
|
case DomainMessageType_Close:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageUnknownType);
|
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageUnknownType);
|
||||||
}
|
}
|
||||||
r->ThisObjectId = hdr->ThisObjectId;
|
|
||||||
r->NumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
|
r->InThisObjectId = hdr->ThisObjectId;
|
||||||
if ((uintptr_t)object_ids + sizeof(u32) * r->NumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
|
r->InNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
|
||||||
|
if ((uintptr_t)object_ids + sizeof(u32) * r->InNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
|
||||||
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
|
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
|
||||||
}
|
}
|
||||||
for(size_t i = 0; i < r->NumObjectIds; i++)
|
for(size_t i = 0; i < r->InNumObjectIds; i++)
|
||||||
r->ObjectIds[i] = object_ids[i];
|
r->InObjectIds[i] = object_ids[i];
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse an IPC command response into an IPC parsed command structure (domain version).
|
||||||
|
* @param IPC parsed command structure to fill in.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
static inline Result ipcParseDomainResponse(IpcParsedCommand* r, size_t sizeof_raw) {
|
||||||
|
Result rc = ipcParse(r);
|
||||||
|
DomainResponseHeader *hdr;
|
||||||
|
u32 *object_ids;
|
||||||
|
if(R_FAILED(rc))
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
hdr = (DomainResponseHeader*) r->Raw;
|
||||||
|
r->Raw = (void*)(((uintptr_t) r->Raw) + sizeof(DomainResponseHeader));
|
||||||
|
object_ids = (u32*)((((uintptr_t) r->Raw) + sizeof_raw + 3) & ~3);
|
||||||
|
|
||||||
|
r->IsDomainResponse = true;
|
||||||
|
|
||||||
|
r->OutNumObjectIds = hdr->NumObjectIds > 8 ? 8 : hdr->NumObjectIds;
|
||||||
|
if ((uintptr_t)object_ids + sizeof(u32) * r->OutNumObjectIds - (uintptr_t)armGetTls() >= 0x100) {
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_DomainMessageTooManyObjectIds);
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < r->OutNumObjectIds; i++)
|
||||||
|
r->OutObjectIds[i] = object_ids[i];
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -704,7 +745,7 @@ static inline Result ipcCloseObjectById(Handle session, u32 object_id) {
|
|||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
hdr = (DomainMessageHeader*)ipcPrepareHeader(&c, sizeof(DomainMessageHeader));
|
hdr = (DomainMessageHeader*)ipcPrepareHeader(&c, sizeof(DomainMessageHeader));
|
||||||
|
|
||||||
hdr->Type = 2;
|
hdr->Type = DomainMessageType_Close;
|
||||||
hdr->NumObjectIds = 0;
|
hdr->NumObjectIds = 0;
|
||||||
hdr->Length = 0;
|
hdr->Length = 0;
|
||||||
hdr->ThisObjectId = object_id;
|
hdr->ThisObjectId = object_id;
|
||||||
|
@ -16,7 +16,7 @@ typedef enum {
|
|||||||
ServiceType_Normal, ///< Normal service.
|
ServiceType_Normal, ///< Normal service.
|
||||||
ServiceType_Domain, ///< Domain.
|
ServiceType_Domain, ///< Domain.
|
||||||
ServiceType_DomainSubservice, ///< Domain subservice;
|
ServiceType_DomainSubservice, ///< Domain subservice;
|
||||||
ServiceType_Override ///< Service overriden in the homebrew environment.
|
ServiceType_Override, ///< Service overriden in the homebrew environment.
|
||||||
} ServiceType;
|
} ServiceType;
|
||||||
|
|
||||||
/// Service object structure.
|
/// Service object structure.
|
||||||
@ -113,15 +113,39 @@ static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u3
|
|||||||
s->object_id = object_id;
|
s->object_id = object_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a subservice object from a parent service.
|
||||||
|
* @param[out] s Service object.
|
||||||
|
* @param[in] parent Parent service, possibly a domain or domain subservice.
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
static inline void serviceCreateSubservice(Service* s, Service* parent, IpcParsedCommand* r, int i) {
|
||||||
|
if (r->IsDomainResponse) {
|
||||||
|
return serviceCreateDomainSubservice(s, parent, r->OutObjectIds[i]);
|
||||||
|
} else {
|
||||||
|
return serviceCreate(s, r->Handles[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts a regular service to a domain.
|
* @brief Converts a regular service to a domain.
|
||||||
* @param[in] s Service object.
|
* @param[in] s Service object.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
*/
|
*/
|
||||||
static inline Result serviceConvertToDomain(Service* s) {
|
static inline Result serviceConvertToDomain(Service* s) {
|
||||||
Result rc = ipcConvertSessionToDomain(s->handle, &s->object_id);
|
Result rc = 0;
|
||||||
if(R_SUCCEEDED(rc))
|
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;
|
s->type = ServiceType_Domain;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +177,37 @@ static inline void serviceClose(Service* s) {
|
|||||||
s->type = ServiceType_Uninitialized;
|
s->type = ServiceType_Uninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepares the header of an IPC command structure for a service.
|
||||||
|
* @param s Service to prepare message header for
|
||||||
|
* @param cmd IPC command structure.
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
static inline void* serviceIpcPrepareHeader(Service* s, IpcCommand* cmd, size_t sizeof_raw) {
|
||||||
|
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
||||||
|
return ipcPrepareHeaderForDomain(cmd, sizeof_raw, serviceGetObjectId(s));
|
||||||
|
} else {
|
||||||
|
return ipcPrepareHeader(cmd, sizeof_raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse an IPC command response into an IPC parsed command structure for a service.
|
||||||
|
* @param s Service to prepare message header for
|
||||||
|
* @param r IPC parsed command structure to fill in.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t sizeof_raw) {
|
||||||
|
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
||||||
|
return ipcParseDomainResponse(r, sizeof_raw);
|
||||||
|
} else {
|
||||||
|
return ipcParse(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes SM.
|
* @brief Initializes SM.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
|
Loading…
Reference in New Issue
Block a user