From 9866f8e8b26ec89743b14cf5db7952d3c55f31f2 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sat, 4 Nov 2017 18:28:13 -0400 Subject: [PATCH] Implemented binder. Added error LIBNX_BADINPUT. Set StrayLayer in viOpenLayer properly. --- nx/include/switch.h | 1 + nx/include/switch/result.h | 1 + nx/include/switch/services/binder.h | 17 +++ nx/source/gfx/gfx.c | 33 ++++++ nx/source/services/binder.c | 167 ++++++++++++++++++++++++++++ nx/source/services/vi.c | 1 + 6 files changed, 220 insertions(+) create mode 100644 nx/include/switch/services/binder.h create mode 100644 nx/source/services/binder.c diff --git a/nx/include/switch.h b/nx/include/switch.h index ab9cba0c..8d485618 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -23,6 +23,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/nx/include/switch/result.h b/nx/include/switch/result.h index 3dec642e..d3f802c3 100644 --- a/nx/include/switch/result.h +++ b/nx/include/switch/result.h @@ -28,3 +28,4 @@ #define LIBNX_NOTINITIALIZED 7 #define LIBNX_NOTFOUND 8 #define LIBNX_IOERROR 9 +#define LIBNX_BADINPUT 10 diff --git a/nx/include/switch/services/binder.h b/nx/include/switch/services/binder.h new file mode 100644 index 00000000..375b3d47 --- /dev/null +++ b/nx/include/switch/services/binder.h @@ -0,0 +1,17 @@ +typedef struct { + bool initialized; + Handle sessionhandle; + s32 ID; + + Handle nativehandle; +} binderSession; + +//binderExitSession will not close the sessionhandle since it's user-specified via binderCreateSession and may be used elsewhere. +void binderCreateSession(binderSession *session, Handle sessionhandle, s32 ID); +Result binderInitSession(binderSession *session, u32 nativehandle_inval);/// nativehandle_inval is the inval for binderGetNativeHandle. +Result binderExitSession(binderSession *session); + +Result binderTransactParcel(binderSession *session, u32 code, void* parcel_data, size_t parcel_data_size, void* parcel_reply, size_t parcel_reply_size, u32 flags); +Result binderAdjustRefcount(binderSession *session, s32 addval, s32 type); +Result binderGetNativeHandle(binderSession *session, u32 inval, Handle *handle_out); + diff --git a/nx/source/gfx/gfx.c b/nx/source/gfx/gfx.c index 115d8089..29b77d6e 100644 --- a/nx/source/gfx/gfx.c +++ b/nx/source/gfx/gfx.c @@ -6,12 +6,31 @@ static viDisplay g_gfxDisplay; static viLayer g_gfxLayer; static u8 g_gfxNativeWindow[0x100]; static u64 g_gfxNativeWindow_Size; +static s32 g_gfxNativeWindow_ID; +static binderSession g_gfxBinderSession; + +static Result _gfxGetNativeWindowID(u8 *buf, u64 size, s32 *out_ID) { + u32 *bufptr = (u32*)buf; + + //Validate ParcelData{Size|Offset}. + if((u64)bufptr[1] >= size || (u64)bufptr[0] >= size || ((u64)bufptr[1])+((u64)bufptr[0]) >= size) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT); + if(bufptr[0] < 0xc) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT); + + //bufptr = start of ParcelData + bufptr = (u32*)&buf[bufptr[1]]; + + *out_ID = (s32)bufptr[2]; + + return 0; +} static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 LayerFlags, u64 LayerId) { Result rc=0; if(g_gfxInitialized)return 0; + g_gfxNativeWindow_ID = 0; + rc = viInitialize(servicetype); if (R_FAILED(rc)) return rc; @@ -19,7 +38,18 @@ static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 L if (R_SUCCEEDED(rc)) rc = viOpenLayer(g_gfxNativeWindow, &g_gfxNativeWindow_Size, &g_gfxDisplay, &g_gfxLayer, LayerFlags, LayerId); + if (R_SUCCEEDED(rc)) rc = _gfxGetNativeWindowID(g_gfxNativeWindow, g_gfxNativeWindow_Size, &g_gfxNativeWindow_ID); + + if (R_SUCCEEDED(rc)) { + binderCreateSession(&g_gfxBinderSession, viGetSession_IHOSBinderDriverRelay(), g_gfxNativeWindow_ID); + rc = binderInitSession(&g_gfxBinderSession, 0x0f); + } + + //TODO: Send binder parcels. + if (R_FAILED(rc)) { + binderExitSession(&g_gfxBinderSession); + viCloseLayer(&g_gfxLayer); viCloseDisplay(&g_gfxDisplay); viExit(); } @@ -37,11 +67,14 @@ void gfxInitDefault(void) { void gfxExit(void) { if(!g_gfxInitialized)return; + binderExitSession(&g_gfxBinderSession); + viCloseLayer(&g_gfxLayer); viCloseDisplay(&g_gfxDisplay); viExit(); g_gfxInitialized = 0; + g_gfxNativeWindow_ID = 0; } diff --git a/nx/source/services/binder.c b/nx/source/services/binder.c new file mode 100644 index 00000000..58110aed --- /dev/null +++ b/nx/source/services/binder.c @@ -0,0 +1,167 @@ +#include +#include + +void binderCreateSession(binderSession *session, Handle sessionhandle, s32 ID) { + memset(session, 0, sizeof(binderSession)); + session->sessionhandle = sessionhandle; + session->ID = ID; + session->initialized = 1; +} + +Result binderInitSession(binderSession *session, u32 nativehandle_inval) { + Result rc = 0; + + rc = binderAdjustRefcount(session, 1, 0); + if (R_FAILED(rc)) return rc; + + rc = binderAdjustRefcount(session, 1, 1); + if (R_FAILED(rc)) return rc; + + rc = binderGetNativeHandle(session, nativehandle_inval, &session->nativehandle); + if (R_FAILED(rc)) return rc; + + //When the output nativehandle is 0 the binderSession ID is probably invalid. + if(session->nativehandle == 0) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT); + + return 0; +} + +Result binderExitSession(binderSession *session) { + Result rc = 0; + + if(!session->initialized)return 0; + + rc = binderAdjustRefcount(session, -1, 1); + + if (R_SUCCEEDED(rc)) rc = binderAdjustRefcount(session, -1, 0); + + if(session->nativehandle) { + svcCloseHandle(session->nativehandle); + session->nativehandle = 0; + } + + session->initialized = 0; + + return rc; +} + +static Result _binderTransactParcel(binderSession *session, u32 code, void* parcel_data, size_t parcel_data_size, void* parcel_reply, size_t parcel_reply_size, u32 flags) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + s32 ID; + u32 code; + u32 flags; + } *raw; + + ipcAddSendBuffer(&c, parcel_data, parcel_data_size, 0); + ipcAddRecvBuffer(&c, parcel_reply, parcel_reply_size, 0); + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->ID = session->ID; + raw->code = code; + raw->flags = flags; + + Result rc = ipcDispatch(session->sessionhandle); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +//TODO: Use TransactParcelAuto when it's available. + +Result binderTransactParcel(binderSession *session, u32 code, void* parcel_data, size_t parcel_data_size, void* parcel_reply, size_t parcel_reply_size, u32 flags) { + return _binderTransactParcel(session, code, parcel_data, parcel_data_size, parcel_reply, parcel_reply_size, flags); +} + +Result binderAdjustRefcount(binderSession *session, s32 addval, s32 type) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + s32 ID; + s32 addval; + s32 type; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1; + raw->ID = session->ID; + raw->addval = addval; + raw->type = type; + + Result rc = ipcDispatch(session->sessionhandle); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result binderGetNativeHandle(binderSession *session, u32 inval, Handle *handle_out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + s32 ID; + u32 inval; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2; + raw->ID = session->ID; + raw->inval = inval; + + Result rc = ipcDispatch(session->sessionhandle); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *handle_out = r.Handles[0]; + } + } + + return rc; +} + diff --git a/nx/source/services/vi.c b/nx/source/services/vi.c index cf8e65db..475d7dd1 100644 --- a/nx/source/services/vi.c +++ b/nx/source/services/vi.c @@ -340,6 +340,7 @@ Result viOpenLayer(u8 NativeWindow[0x100], u64 *NativeWindow_Size, const viDispl if (LayerId==0) rc = appletGetAppletResourceUserId(&AppletResourceUserId); if (LayerId==0 && (R_FAILED(rc) || AppletResourceUserId == 0)) { rc = _viCreateStrayLayer(NativeWindow, NativeWindow_Size, display, LayerFlags, &layer->LayerId); + if (R_SUCCEEDED(rc)) layer->StrayLayer = 1; } else { if (LayerId==0) {