libctru/libctru/source/srv.c
fincs 2797540a3d Revise most services to follow these guidelines:
- Each service must have xyzInit/xyzExit (with that name)
- xyzInit/xyzExit use reference counting
- xyzExit returns void
- The utilities in <3ds/result.h> are used instead of manual error checking
- The intrinsics in <3ds/synchronization.h> are used instead of inline asm
- Other miscellaneous changes
  - APT now uses a lightweight lock instead of a mutex
  - Initial handle parameters in PTMU were killed
  - Explicit init'ion to 0 or NULL has been removed for global variables
    since they end up on .bss anyway
  - MIC hasn't been touched because it must be rewritten first
  - CFGNOR needs a slight touch before converting
  - SOC is still to be cleaned up
2015-11-07 01:25:31 +01:00

224 lines
4.5 KiB
C

/*
srv.c _ Service manager.
*/
#include <string.h>
#include <3ds/types.h>
#include <3ds/result.h>
#include <3ds/srv.h>
#include <3ds/svc.h>
#include <3ds/ipc.h>
/*
The homebrew loader can choose to supply a list of service handles that have
been "stolen" from other processes that have been compromised. This allows us
to access services that are normally restricted from the current process.
For every service requested by the application, we shall first check if the
list given to us contains the requested service and if so use it. If we don't
find the service in that list, we ask the service manager and hope for the
best.
*/
typedef struct {
u32 num;
struct {
char name[8];
Handle handle;
} services[];
} service_list_t;
extern service_list_t* __service_ptr;
static Handle g_srv_handle;
static int __name_cmp(const char* a, const char* b) {
u32 i;
for(i=0; i<8; i++) {
if(a[i] != b[i])
return 1;
if(a[i] == '\0')
return 0;
}
return 0;
}
Handle __get_handle_from_list(const char* name) {
if((u32)__service_ptr == 0)
return 0;
u32 i, num = __service_ptr->num;
for(i=0; i<num; i++) {
if(__name_cmp(__service_ptr->services[i].name, name) == 0)
return __service_ptr->services[i].handle;
}
return 0;
}
void __destroy_handle_list(void) {
if((u32)__service_ptr == 0)
return;
u32 i, num = __service_ptr->num;
for(i=0; i<num; i++)
svcCloseHandle(__service_ptr->services[i].handle);
__service_ptr->num = 0;
}
Result srvInit(void)
{
Result rc = 0;
if(g_srv_handle != 0) return rc;
if(R_FAILED(rc = svcConnectToPort(&g_srv_handle, "srv:")))return rc;
if(R_FAILED(rc = srvRegisterClient())) {
svcCloseHandle(g_srv_handle);
g_srv_handle = 0;
}
return rc;
}
Result srvExit(void)
{
if(g_srv_handle != 0)svcCloseHandle(g_srv_handle);
g_srv_handle = 0;
return 0;
}
Handle *srvGetSessionHandle(void)
{
return &g_srv_handle;
}
Result srvRegisterClient(void)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x1,0,2); // 0x10002
cmdbuf[1] = IPC_Desc_CurProcessHandle();
if(R_FAILED(rc = svcSendSyncRequest(g_srv_handle)))return rc;
return cmdbuf[1];
}
Result srvGetServiceHandleDirect(Handle* out, const char* name)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x5,4,0); // 0x50100
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strlen(name);
cmdbuf[4] = 0x0;
if(R_FAILED(rc = svcSendSyncRequest(g_srv_handle)))return rc;
*out = cmdbuf[3];
return cmdbuf[1];
}
Result srvGetServiceHandle(Handle* out, const char* name)
{
/* Look in service-list given to us by loader. If we find find a match,
we return it. */
Handle h = __get_handle_from_list(name);
if(h != 0) {
return svcDuplicateHandle(out, h);
}
/* Normal request to service manager. */
return srvGetServiceHandleDirect(out, name);
}
Result srvRegisterService(Handle* out, const char* name, int maxSessions)
{
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x3,4,0); // 0x30100
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strlen(name);
cmdbuf[4] = maxSessions;
Result rc;
if(R_FAILED(rc = svcSendSyncRequest(g_srv_handle)))return rc;
*out = cmdbuf[3];
return cmdbuf[1];
}
Result srvUnregisterService(const char* name)
{
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x4,3,0); // 0x400C0
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strlen(name);
Result rc;
if(R_FAILED(rc = svcSendSyncRequest(g_srv_handle)))return rc;
return cmdbuf[1];
}
// Old srv:pm interface, will only work on systems where srv:pm was a port (<7.X)
Result srvPmInit(void)
{
Result rc = 0;
if(R_FAILED(rc = svcConnectToPort(&g_srv_handle, "srv:pm")))return rc;
if(R_FAILED(rc = srvRegisterClient())) {
svcCloseHandle(g_srv_handle);
g_srv_handle = 0;
}
return rc;
}
Result srvRegisterProcess(u32 procid, u32 count, void *serviceaccesscontrol)
{
Result rc = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x403,2,2); // 0x4030082 // <7.x
cmdbuf[1] = procid;
cmdbuf[2] = count;
cmdbuf[3] = IPC_Desc_StaticBuffer(count*4,0);
cmdbuf[4] = (u32)serviceaccesscontrol;
if(R_FAILED(rc = svcSendSyncRequest(g_srv_handle))) return rc;
return cmdbuf[1];
}
Result srvUnregisterProcess(u32 procid)
{
Result rc = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x404,1,0); // 0x4040040 // <7.x
cmdbuf[1] = procid;
if(R_FAILED(rc = svcSendSyncRequest(g_srv_handle))) return rc;
return cmdbuf[1];
}