mirror of
https://github.com/switchbrew/libnx.git
synced 2025-08-05 07:59:24 +02:00
Added svcGetSystemTick. Added LIBNX_PARCEL_ERRBASE to result.h. Added BINDER_FIRST_CALL_TRANSACTION. Added gfxproducer and parcel. Use gfxproducer in gfx and added gfxSwapBuffers().
This commit is contained in:
parent
b5abd52b8b
commit
1d8c51f6fa
@ -32,6 +32,8 @@ extern "C" {
|
||||
#include <switch/services/vi.h>
|
||||
|
||||
#include <switch/gfx/gfx.h>
|
||||
#include <switch/gfx/parcel.h>
|
||||
#include <switch/gfx/gfxproducer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -2,3 +2,4 @@
|
||||
void gfxInitDefault(void);
|
||||
void gfxExit(void);
|
||||
void gfxWaitForVsync();
|
||||
void gfxSwapBuffers();
|
||||
|
9
nx/include/switch/gfx/gfxproducer.h
Normal file
9
nx/include/switch/gfx/gfxproducer.h
Normal file
@ -0,0 +1,9 @@
|
||||
Result gfxproducerInitialize(binderSession *session);
|
||||
void gfxproducerExit();
|
||||
|
||||
Result gfxproducerRequestBuffer(s32 bufferIdx);
|
||||
Result gfxproducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage);
|
||||
Result gfxproducerQueueBuffer(s32 buf, u8 input[0x5c]);
|
||||
Result gfxproducerQuery(s32 what, s32* value);
|
||||
Result gfxproducerConnect(s32 api, bool producerControlledByApp);
|
||||
Result gfxproducerBufferInit(s32 buf, u8 input[0x178]);
|
28
nx/include/switch/gfx/parcel.h
Normal file
28
nx/include/switch/gfx/parcel.h
Normal file
@ -0,0 +1,28 @@
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
|
||||
typedef struct {
|
||||
u8 ParcelData[0x400];
|
||||
u32 ParcelData_maxsize;
|
||||
u32 ParcelData_size;
|
||||
u32 ParcelData_pos;
|
||||
|
||||
u8 *ParcelObjects;
|
||||
u32 ParcelObjectsSize;
|
||||
} parcelContext;
|
||||
|
||||
void parcelInitializeContext(parcelContext *ctx);
|
||||
Result parcelTransact(binderSession *session, u32 code, parcelContext *in_parcel, parcelContext *out_parcel);
|
||||
|
||||
void* parcelWriteData(parcelContext *ctx, void* data, size_t data_size);
|
||||
void* parcelReadData(parcelContext *ctx, void* data, size_t data_size);
|
||||
|
||||
void parcelWriteInt32(parcelContext *ctx, s32 val);
|
||||
void parcelWriteUInt32(parcelContext *ctx, u32 val);
|
||||
void parcelWriteString16_fromchar(parcelContext *ctx, const char *str);
|
||||
|
||||
void parcelWriteInterfaceToken(parcelContext *ctx, const char *interface);
|
||||
|
||||
s32 parcelReadInt32(parcelContext *ctx);
|
||||
u32 parcelReadUInt32(parcelContext *ctx);
|
||||
|
@ -29,3 +29,4 @@
|
||||
#define LIBNX_NOTFOUND 8
|
||||
#define LIBNX_IOERROR 9
|
||||
#define LIBNX_BADINPUT 10
|
||||
#define LIBNX_PARCEL_ERRBASE 100
|
||||
|
@ -1,3 +1,5 @@
|
||||
#define BINDER_FIRST_CALL_TRANSACTION 0x1
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
Handle sessionhandle;
|
||||
|
@ -45,6 +45,7 @@ Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount
|
||||
Result svcArbitrateLock(u32 wait_tag, u32* tag_location, u32 self_tag);
|
||||
Result svcArbitrateUnlock(u32* tag_location);
|
||||
Result svcConnectToNamedPort(Handle* session, const char* name);
|
||||
u64 svcGetSystemTick(void);
|
||||
Result svcSendSyncRequest(Handle session);
|
||||
Result svcBreak(u32 breakReason, u64 inval1, u64 inval2);
|
||||
Result svcGetInfo(u64* out, u64 id0, Handle handle, u64 id1);
|
||||
|
@ -9,6 +9,50 @@ static u8 g_gfxNativeWindow[0x100];
|
||||
static u64 g_gfxNativeWindow_Size;
|
||||
static s32 g_gfxNativeWindow_ID;
|
||||
static binderSession g_gfxBinderSession;
|
||||
static s32 g_gfxCurrentBuffer = 0;
|
||||
|
||||
static u32 g_gfxQueueBufferData[0x5c>>2] = {
|
||||
0x54, 0x0,
|
||||
0x0, 0x0, //u64 timestamp
|
||||
0x1, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2,
|
||||
0x0, 0x0, 0x1, 0x1,
|
||||
0x42,
|
||||
0x13f4, //Increased by 6/7 each time.
|
||||
0xffffffff, 0x0,
|
||||
0xffffffff, 0x0, 0xffffffff, 0x0};
|
||||
|
||||
static u32 g_gfxBufferInitData[0x178>>2] = {
|
||||
0x1, 0x16c, 0x0,
|
||||
0x47424652,
|
||||
1280, 720,
|
||||
1280,
|
||||
0x1, 0xb00, 0x2a, 0x0,
|
||||
0x0, 0x51, 0xffffffff, 0xcb8,
|
||||
0x0, 0xdaffcaff, 0x2a, 0x0,
|
||||
0xb00, 0x1, 0x1, 1280,
|
||||
0x3c0000, 0x1, 0x0, 1280,
|
||||
720, 0x532120, 0x1, 0x3,
|
||||
0x1400, 0xcb8,
|
||||
0x0,
|
||||
0xfe,
|
||||
0x4, 0x0, 0x0, 0x0,
|
||||
0x0, 0x3c0000, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0,
|
||||
0x0, 0x0 //Unknown, some timestamp perhaps?
|
||||
};
|
||||
|
||||
static Result _gfxGetNativeWindowID(u8 *buf, u64 size, s32 *out_ID) {
|
||||
u32 *bufptr = (u32*)buf;
|
||||
@ -25,13 +69,38 @@ static Result _gfxGetNativeWindowID(u8 *buf, u64 size, s32 *out_ID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Result _gfxDequeueBuffer() {
|
||||
return gfxproducerDequeueBuffer(1, 1280, 720, 0, 0x300);
|
||||
}
|
||||
|
||||
static Result _gfxQueueBuffer(s32 buf) {
|
||||
Result rc=0;
|
||||
u64 *ptr64 = (u64*)&g_gfxQueueBufferData;
|
||||
ptr64[1] = svcGetSystemTick();//Unknown what is actually used for timestamp, but shouldn't(?) matter.
|
||||
|
||||
rc = gfxproducerQueueBuffer(buf, (u8*)g_gfxQueueBufferData);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
if(buf==0) {
|
||||
g_gfxQueueBufferData[0x10]+= 0x6;
|
||||
} else {
|
||||
g_gfxQueueBufferData[0x10]+= 0x7;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 LayerFlags, u64 LayerId) {
|
||||
Result rc=0;
|
||||
s32 tmp=0;
|
||||
u32 i=0;
|
||||
u64 *ptr64 = (u64*)g_gfxQueueBufferData;
|
||||
|
||||
if(g_gfxInitialized)return 0;
|
||||
|
||||
g_gfxNativeWindow_ID = 0;
|
||||
g_gfxDisplayVsyncEvent = INVALID_HANDLE;
|
||||
g_gfxCurrentBuffer = 0;
|
||||
|
||||
rc = viInitialize(servicetype);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
@ -51,7 +120,36 @@ static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 L
|
||||
rc = binderInitSession(&g_gfxBinderSession, 0x0f);
|
||||
}
|
||||
|
||||
//TODO: Send binder parcels.
|
||||
if (R_SUCCEEDED(rc)) rc = gfxproducerInitialize(&g_gfxBinderSession);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = gfxproducerConnect(2, 0);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = gfxproducerQuery(2, &tmp);//"NATIVE_WINDOW_FORMAT"
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
for(i=0; i<2; i++) {
|
||||
g_gfxBufferInitData[0xa] = i;
|
||||
g_gfxBufferInitData[0x20] = 0x3c0000*i;
|
||||
ptr64[0x170>>3] = svcGetSystemTick();
|
||||
rc = gfxproducerBufferInit(0, (u8*)g_gfxBufferInitData);
|
||||
if (R_FAILED(rc)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
for(i=0; i<2; i++) {
|
||||
rc = _gfxDequeueBuffer();
|
||||
if (R_FAILED(rc)) break;
|
||||
|
||||
rc = gfxproducerRequestBuffer(i);
|
||||
if (R_FAILED(rc)) break;
|
||||
|
||||
rc = _gfxQueueBuffer(i);
|
||||
if (R_FAILED(rc)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer();
|
||||
|
||||
if (R_FAILED(rc)) {
|
||||
binderExitSession(&g_gfxBinderSession);
|
||||
@ -73,6 +171,8 @@ void gfxInitDefault(void) {
|
||||
void gfxExit(void) {
|
||||
if(!g_gfxInitialized)return;
|
||||
|
||||
gfxproducerExit();
|
||||
|
||||
binderExitSession(&g_gfxBinderSession);
|
||||
|
||||
viCloseLayer(&g_gfxLayer);
|
||||
@ -96,3 +196,14 @@ void gfxWaitForVsync() {
|
||||
svcWaitSynchronization(&tmpindex, &g_gfxDisplayVsyncEvent, 1, U64_MAX);
|
||||
}
|
||||
|
||||
void gfxSwapBuffers() {
|
||||
Result rc=0;
|
||||
|
||||
rc = _gfxQueueBuffer(g_gfxCurrentBuffer);
|
||||
g_gfxCurrentBuffer ^= 1;
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _gfxDequeueBuffer();
|
||||
|
||||
if (R_FAILED(rc)) fatalSimple(rc);
|
||||
}
|
||||
|
||||
|
175
nx/source/gfx/gfxproducer.c
Normal file
175
nx/source/gfx/gfxproducer.c
Normal file
@ -0,0 +1,175 @@
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
|
||||
//This implements the version of Android IGraphicBufferProducer used by Switch, hence names/params etc here are based on Android IGraphicBufferProducer.cpp.
|
||||
|
||||
//Based on an old version of the enum from the above .cpp.
|
||||
//Unknown whether all of these are correct for Switch.
|
||||
enum {
|
||||
REQUEST_BUFFER = BINDER_FIRST_CALL_TRANSACTION, //0x1
|
||||
SET_BUFFER_COUNT, //0x2
|
||||
DEQUEUE_BUFFER, //0x3
|
||||
DETACH_BUFFER, //0x4
|
||||
DETACH_NEXT_BUFFER, //0x5
|
||||
ATTACH_BUFFER, //0x6
|
||||
QUEUE_BUFFER, //0x7
|
||||
CANCEL_BUFFER, //0x8
|
||||
QUERY, //0x9
|
||||
CONNECT, //0xA
|
||||
DISCONNECT, //0xB
|
||||
SET_SIDEBAND_STREAM, //0xC
|
||||
ALLOCATE_BUFFERS, //0xD
|
||||
};
|
||||
|
||||
static char _gfxproducer_InterfaceDescriptor[] = "android.gui.IGraphicBufferProducer";
|
||||
|
||||
static binderSession *g_gfxproducerBinderSession;
|
||||
|
||||
Result gfxproducerInitialize(binderSession *session) {
|
||||
g_gfxproducerBinderSession = session;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gfxproducerExit() {
|
||||
g_gfxproducerBinderSession = NULL;
|
||||
}
|
||||
|
||||
Result gfxproducerRequestBuffer(s32 bufferIdx) {
|
||||
Result rc;
|
||||
parcelContext parcel, parcel_reply;
|
||||
|
||||
if (g_gfxproducerBinderSession==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
parcelInitializeContext(&parcel);
|
||||
parcelInitializeContext(&parcel_reply);
|
||||
|
||||
parcelWriteInterfaceToken(&parcel, _gfxproducer_InterfaceDescriptor);
|
||||
parcelWriteInt32(&parcel, bufferIdx);
|
||||
|
||||
rc = parcelTransact(g_gfxproducerBinderSession, REQUEST_BUFFER, &parcel, &parcel_reply);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//TODO: parse reply
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result gfxproducerDequeueBuffer(bool async, u32 width, u32 height, s32 format, u32 usage) {
|
||||
Result rc;
|
||||
parcelContext parcel, parcel_reply;
|
||||
|
||||
if (g_gfxproducerBinderSession==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
parcelInitializeContext(&parcel);
|
||||
parcelInitializeContext(&parcel_reply);
|
||||
|
||||
parcelWriteInterfaceToken(&parcel, _gfxproducer_InterfaceDescriptor);
|
||||
|
||||
parcelWriteInt32(&parcel, async);
|
||||
parcelWriteUInt32(&parcel, width);
|
||||
parcelWriteUInt32(&parcel, height);
|
||||
parcelWriteInt32(&parcel, format);
|
||||
parcelWriteUInt32(&parcel, usage);
|
||||
|
||||
rc = parcelTransact(g_gfxproducerBinderSession, DEQUEUE_BUFFER, &parcel, &parcel_reply);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//TODO: parse reply
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result gfxproducerQueueBuffer(s32 buf, u8 input[0x5c]) {
|
||||
Result rc;
|
||||
parcelContext parcel, parcel_reply;
|
||||
|
||||
if (g_gfxproducerBinderSession==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
parcelInitializeContext(&parcel);
|
||||
parcelInitializeContext(&parcel_reply);
|
||||
|
||||
parcelWriteInterfaceToken(&parcel, _gfxproducer_InterfaceDescriptor);
|
||||
|
||||
parcelWriteInt32(&parcel, buf);
|
||||
parcelWriteData(&parcel, input, 0x5c);
|
||||
|
||||
rc = parcelTransact(g_gfxproducerBinderSession, DEQUEUE_BUFFER, &parcel, &parcel_reply);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//TODO: parse reply
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result gfxproducerQuery(s32 what, s32* value) {
|
||||
Result rc;
|
||||
parcelContext parcel, parcel_reply;
|
||||
|
||||
if (g_gfxproducerBinderSession==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
parcelInitializeContext(&parcel);
|
||||
parcelInitializeContext(&parcel_reply);
|
||||
|
||||
parcelWriteInterfaceToken(&parcel, _gfxproducer_InterfaceDescriptor);
|
||||
|
||||
parcelWriteInt32(&parcel, what);
|
||||
|
||||
rc = parcelTransact(g_gfxproducerBinderSession, QUERY, &parcel, &parcel_reply);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
*value = parcelReadInt32(&parcel_reply);
|
||||
rc = parcelReadInt32(&parcel_reply);
|
||||
if (rc) rc = MAKERESULT(MODULE_LIBNX, LIBNX_PARCEL_ERRBASE);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result gfxproducerConnect(s32 api, bool producerControlledByApp) {
|
||||
Result rc;
|
||||
parcelContext parcel, parcel_reply;
|
||||
|
||||
if (g_gfxproducerBinderSession==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
parcelInitializeContext(&parcel);
|
||||
parcelInitializeContext(&parcel_reply);
|
||||
|
||||
parcelWriteInterfaceToken(&parcel, _gfxproducer_InterfaceDescriptor);
|
||||
|
||||
//Hard-code this as if listener==NULL, since that's not known to be used officially.
|
||||
parcelWriteInt32(&parcel, 0);
|
||||
|
||||
parcelWriteInt32(&parcel, api);
|
||||
parcelWriteInt32(&parcel, producerControlledByApp);
|
||||
|
||||
rc = parcelTransact(g_gfxproducerBinderSession, CONNECT, &parcel, &parcel_reply);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//TODO: parse reply
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Unknown what this is.
|
||||
Result gfxproducerBufferInit(s32 buf, u8 input[0x178]) {
|
||||
Result rc;
|
||||
parcelContext parcel, parcel_reply;
|
||||
|
||||
if (g_gfxproducerBinderSession==NULL) return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
parcelInitializeContext(&parcel);
|
||||
parcelInitializeContext(&parcel_reply);
|
||||
|
||||
parcelWriteInterfaceToken(&parcel, _gfxproducer_InterfaceDescriptor);
|
||||
|
||||
parcelWriteInt32(&parcel, buf);
|
||||
parcelWriteData(&parcel, input, 0x178);
|
||||
|
||||
rc = parcelTransact(g_gfxproducerBinderSession, 0xE, &parcel, &parcel_reply);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//TODO: parse reply
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
123
nx/source/gfx/parcel.c
Normal file
123
nx/source/gfx/parcel.c
Normal file
@ -0,0 +1,123 @@
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
|
||||
//This implements Android Parcel, hence names etc here are based on Android Parcel.cpp.
|
||||
|
||||
/*u8 parcel_reply_log[0x10000] = {0};
|
||||
size_t parcel_reply_log_size = 0;*/
|
||||
|
||||
void parcelInitializeContext(parcelContext *ctx) {
|
||||
memset(ctx, 0, sizeof(parcelContext));
|
||||
ctx->ParcelData_maxsize = sizeof(ctx->ParcelData);
|
||||
}
|
||||
|
||||
//outparcel is allzero with this. This is presumably invalid?
|
||||
Result parcelTransact(binderSession *session, u32 code, parcelContext *in_parcel, parcelContext *out_parcel) {
|
||||
Result rc=0;
|
||||
u8 inparcel[0x400];
|
||||
static u8 outparcel[0x1000];
|
||||
size_t outparcel_size = 0x1000;
|
||||
u32 *inparcel32 = (u32*)inparcel;
|
||||
u32 *outparcel32 = (u32*)outparcel;
|
||||
u32 ParcelDataSize = in_parcel->ParcelData_size;
|
||||
u32 ParcelObjectsSize = in_parcel->ParcelObjectsSize;
|
||||
|
||||
memset(inparcel, 0, sizeof(inparcel));
|
||||
memset(outparcel, 0, outparcel_size);
|
||||
|
||||
if((size_t)ParcelDataSize >= sizeof(inparcel) || (size_t)ParcelObjectsSize >= sizeof(inparcel) || ((size_t)ParcelDataSize)+((size_t)ParcelObjectsSize)+0x10 >= sizeof(inparcel)) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT);
|
||||
|
||||
inparcel32[0] = ParcelDataSize;//ParcelDataSize
|
||||
inparcel32[1] = 0x10;//ParcelDataOffset
|
||||
inparcel32[2] = ParcelObjectsSize;//ParcelObjectsSize
|
||||
inparcel32[3] = 0x10+ParcelDataSize;//ParcelObjectsOffset
|
||||
|
||||
if(in_parcel->ParcelData && ParcelDataSize)memcpy(&inparcel[inparcel32[1]], in_parcel->ParcelData, ParcelDataSize);
|
||||
if(in_parcel->ParcelObjects && ParcelObjectsSize)memcpy(&inparcel[inparcel32[3]], in_parcel->ParcelObjects, ParcelObjectsSize);
|
||||
|
||||
rc = binderTransactParcel(session, code, inparcel, ParcelDataSize+ParcelObjectsSize+0x10, outparcel, outparcel_size, 0);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
if((size_t)outparcel32[1] >= outparcel_size || ((size_t)outparcel32[0])+((size_t)outparcel32[1]) >= outparcel_size) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT);
|
||||
if((size_t)outparcel32[2] >= outparcel_size || ((size_t)outparcel32[2])+((size_t)outparcel32[3]) >= outparcel_size) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT);
|
||||
if((size_t)outparcel32[0] >= outparcel_size || (size_t)outparcel32[3] >= outparcel_size) return MAKERESULT(MODULE_LIBNX, LIBNX_BADINPUT);
|
||||
|
||||
memcpy(out_parcel->ParcelData, &outparcel[outparcel32[1]], outparcel32[0]);
|
||||
out_parcel->ParcelData_size = outparcel32[0];
|
||||
|
||||
/*memcpy(&parcel_reply_log[parcel_reply_log_size], out_parcel, outparcel_size);
|
||||
parcel_reply_log_size+= outparcel_size;*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* parcelWriteData(parcelContext *ctx, void* data, size_t data_size) {
|
||||
void* ptr = ctx->ParcelData;
|
||||
|
||||
if(data_size & BIT(31)) return NULL;
|
||||
data_size = (data_size+3) & ~3;
|
||||
|
||||
if(ctx->ParcelData_size + data_size >= ctx->ParcelData_maxsize) return NULL;
|
||||
|
||||
if(data)memcpy(&ctx->ParcelData[ctx->ParcelData_size], data, data_size);
|
||||
ctx->ParcelData_size+= data_size;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* parcelReadData(parcelContext *ctx, void* data, size_t data_size) {
|
||||
void* ptr = ctx->ParcelData;
|
||||
size_t aligned_data_size;
|
||||
|
||||
if(data_size & BIT(31)) return NULL;
|
||||
aligned_data_size = (data_size+3) & ~3;
|
||||
|
||||
if(ctx->ParcelData_pos + aligned_data_size >= ctx->ParcelData_size) return NULL;
|
||||
|
||||
if(data)memcpy(data, &ctx->ParcelData[ctx->ParcelData_pos], data_size);
|
||||
ctx->ParcelData_pos+= aligned_data_size;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void parcelWriteInt32(parcelContext *ctx, s32 val) {
|
||||
parcelWriteData(ctx, &val, sizeof(val));
|
||||
}
|
||||
|
||||
void parcelWriteUInt32(parcelContext *ctx, u32 val) {
|
||||
parcelWriteData(ctx, &val, sizeof(val));
|
||||
}
|
||||
|
||||
void parcelWriteString16_fromchar(parcelContext *ctx, const char *str) {
|
||||
u32 pos, len;
|
||||
u16 *ptr;
|
||||
|
||||
len = strlen(str);
|
||||
parcelWriteInt32(ctx, len);
|
||||
len++;
|
||||
|
||||
ptr = parcelWriteData(ctx, NULL, len*2);
|
||||
if(ptr==NULL)return;
|
||||
|
||||
for(pos=0; pos<len; pos++) {
|
||||
ptr[pos] = (u16)str[pos];
|
||||
}
|
||||
}
|
||||
|
||||
void parcelWriteInterfaceToken(parcelContext *ctx, const char *interface) {
|
||||
parcelWriteInt32(ctx, 0x100);
|
||||
parcelWriteString16_fromchar(ctx, interface);
|
||||
}
|
||||
|
||||
s32 parcelReadInt32(parcelContext *ctx) {
|
||||
s32 val = 0;
|
||||
parcelReadData(ctx, &val, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 parcelReadUInt32(parcelContext *ctx) {
|
||||
u32 val = 0;
|
||||
parcelReadData(ctx, &val, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
@ -118,6 +118,11 @@ SVC_BEGIN svcConnectToNamedPort
|
||||
ret
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcGetSystemTick
|
||||
svc 0x1E
|
||||
ret
|
||||
SVC_END
|
||||
|
||||
SVC_BEGIN svcSendSyncRequest
|
||||
svc 0x21
|
||||
ret
|
||||
|
Loading…
Reference in New Issue
Block a user