blob: 00729f4a549c818fb72ce4e3c70ba2a4c8641d1d [file] [log] [blame]
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#include "qurt_mutex.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <pthread.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <sys/eventfd.h>
#include "platform_libs.h"
#include "HAP_farf.h"
#include "verify.h"
#include "mod_table.h"
#include "remote_priv.h"
#include "rpcmem.h"
#include "adsp_listener.h"
#include "listener_buf.h"
#include "shared.h"
#include "AEEstd.h"
#include "fastrpc_apps_user.h"
#include "AEEStdErr.h"
#define LOGL(format, ...) VERIFY_PRINT_INFO(format, ##__VA_ARGS__)
#ifndef MALLOC
#define MALLOC malloc
#endif
#ifndef CALLOC
#define CALLOC calloc
#endif
#ifndef FREE
#define FREE free
#endif
#ifndef REALLOC
#define REALLOC realloc
#endif
#ifndef FREEIF
#define FREEIF(pv) \
do {\
if(pv) { \
void* tmp = (void*)pv;\
pv = 0;\
FREE(tmp);\
} \
} while(0)
#endif
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/eventfd.h>
struct listener {
pthread_t thread;
int eventfd;
};
static struct listener linfo[NUM_DOMAINS_EXTEND] =
{ [0 ... NUM_DOMAINS_EXTEND - 1] = { .thread = 0, .eventfd = -1 } };
//TODO: fix this to work over any number of buffers
// needs qaic to support extra buffers
#define MAX_BUFS 250
struct invoke_bufs {
adsp_listener_buffer outbufs[MAX_BUFS];
adsp_listener_buffer inbufs[MAX_BUFS];
int inbufLenReqs[MAX_BUFS];
int outbufLenReqs[MAX_BUFS];
remote_arg args[2*MAX_BUFS];
};
extern void set_thread_context(int domain);
__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_remotectl_open)(const char* name, uint32* handle, char* dlStr, int dlerrorLen, int* dlErr) __QAIC_IMPL_ATTRIBUTE
{
return mod_table_open(name, handle, dlStr, dlerrorLen, dlErr);
}
__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_remotectl_close)(uint32 handle, char* errStr, int errStrLen, int* dlErr) __QAIC_IMPL_ATTRIBUTE
{
return mod_table_close(handle, errStr, errStrLen, dlErr);
}
#define RPC_FREEIF(heapid, buf) \
do {\
if(heapid == -1) {\
FREEIF(buf);\
} else {\
if(buf) {\
rpcmem_free_internal(buf);\
buf = 0;\
}\
}\
} while (0)
static __inline void* rpcmem_realloc(int heapid, uint32 flags, void* buf, int oldsize, int size) {
if(heapid == -1) {
return REALLOC(buf, size);
} else {
void* bufnew = rpcmem_alloc_internal(heapid, flags, size);
if(buf && bufnew) {
memmove(bufnew, buf, oldsize);
rpcmem_free_internal(buf);
buf = NULL;
}
return bufnew;
}
}
static void* listener(void* arg) {
struct listener* me = (struct listener*)arg;
int numOutBufs = 0;
int nErr = AEE_SUCCESS;
adsp_listener_invoke_ctx ctx = 0;
struct invoke_bufs* bufs = 0;
boolean bNeedMore;
int result = -1;
adsp_listener_remote_handle handle;
uint32 sc;
int ii, inBufsAllocated = 0;
const char* eheap = getenv("ADSP_LISTENER_HEAP_ID");
int heapid = eheap == 0 ? 0 : (uint32)atoi(eheap);
const char* eflags = getenv("ADSP_LISTENER_HEAP_FLAGS");
uint32 flags = eflags == 0 ? RPCMEM_HEAP_DEFAULT : (uint32)atoi(eflags);
if(eheap || eflags) {
FARF(HIGH, "listener using ion heap: %d flags: %x\n", (int)heapid, (int)flags);
}
VERIFYC(NULL != (bufs = rpcmem_realloc(heapid, flags, 0, 0, sizeof(*bufs))), AEE_ENORPCMEMORY);
memset(bufs, 0, sizeof(*bufs));
set_thread_context((int)(me - &linfo[0]));
do {
invoke:
bNeedMore = FALSE;
sc = 0xffffffff;
if(result != AEE_SUCCESS) {
numOutBufs = 0;
}
nErr = __QAIC_HEADER(adsp_listener_next_invoke)(
ctx, result, bufs->outbufs, numOutBufs, &ctx,
&handle, &sc, bufs->inbufs, inBufsAllocated,
bufs->inbufLenReqs, MAX_BUFS, bufs->outbufLenReqs, MAX_BUFS);
if(nErr) {
VERIFY_EPRINTF("listener protocol failure %x\n", nErr);
VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_next_invoke)(
ctx, nErr, 0, 0, &ctx,
&handle, &sc, bufs->inbufs, inBufsAllocated,
bufs->inbufLenReqs, MAX_BUFS, bufs->outbufLenReqs, MAX_BUFS)));
}
if(MAX_BUFS < REMOTE_SCALARS_INBUFS(sc) || MAX_BUFS < REMOTE_SCALARS_OUTBUFS(sc)) {
result = AEE_EMAXBUFS;
goto invoke;
}
for(ii = 0; ii < (int)REMOTE_SCALARS_INBUFS(sc); ++ii) {
if(bufs->inbufs[ii].dataLen < bufs->inbufLenReqs[ii]) {
if(0 != bufs->inbufLenReqs[ii]) {
bufs->inbufs[ii].data = rpcmem_realloc(heapid, flags, bufs->inbufs[ii].data, bufs->inbufs[ii].dataLen, bufs->inbufLenReqs[ii]);
if(0 == bufs->inbufs[ii].data) {
bufs->inbufs[ii].dataLen = 0;
result = AEE_ENORPCMEMORY;
goto invoke;
}
}
bufs->inbufs[ii].dataLen = bufs->inbufLenReqs[ii];
inBufsAllocated = STD_MAX(inBufsAllocated, ii + 1);
bNeedMore = TRUE;
}
bufs->args[ii].buf.pv = bufs->inbufs[ii].data;
bufs->args[ii].buf.nLen = bufs->inbufLenReqs[ii];
}
for(ii = 0; ii < (int)REMOTE_SCALARS_OUTBUFS(sc); ++ii) {
if(bufs->outbufs[ii].dataLen < bufs->outbufLenReqs[ii]) {
if(0 != bufs->outbufLenReqs[ii]) {
bufs->outbufs[ii].data = rpcmem_realloc(heapid, flags, bufs->outbufs[ii].data, bufs->outbufs[ii].dataLen, bufs->outbufLenReqs[ii]);
if(0 == bufs->outbufs[ii].data) {
result = AEE_ENORPCMEMORY;
goto invoke;
}
}
bufs->outbufs[ii].dataLen = bufs->outbufLenReqs[ii];
}
bufs->args[ii + REMOTE_SCALARS_INBUFS(sc)].buf.pv = bufs->outbufs[ii].data;
bufs->args[ii + REMOTE_SCALARS_INBUFS(sc)].buf.nLen = bufs->outbufLenReqs[ii];
}
numOutBufs = REMOTE_SCALARS_OUTBUFS(sc);
if(bNeedMore) {
assert(inBufsAllocated >= REMOTE_SCALARS_INBUFS(sc));
if(0 != (result = __QAIC_HEADER(adsp_listener_invoke_get_in_bufs)(ctx, bufs->inbufs,
REMOTE_SCALARS_INBUFS(sc)))) {
FARF(HIGH, "adsp_listener_invoke_get_in_bufs failed %x\n", result);
goto invoke;
}
}
result = mod_table_invoke(handle, sc, bufs->args);
} while(1);
bail:
for(ii = 0; ii < MAX_BUFS && bufs; ++ii) {
RPC_FREEIF(heapid, bufs->outbufs[ii].data);
RPC_FREEIF(heapid, bufs->inbufs[ii].data);
}
RPC_FREEIF(heapid, bufs);
if(nErr != AEE_SUCCESS) {
VERIFY_EPRINTF("Error %x: listener thread exiting\n", nErr);
}
return (void*)(uintptr_t)nErr;
}
static int listener_start_thread(struct listener* me) {
return pthread_create(&me->thread, 0, listener, (void*)me);
}
#define MIN_BUF_SIZE 0x1000
#define ALIGNB(sz) ((sz) == 0 ? MIN_BUF_SIZE : _SBUF_ALIGN((sz), MIN_BUF_SIZE))
static void* listener2(void* arg) {
struct listener* me = (struct listener*)arg;
int nErr = AEE_SUCCESS;
adsp_listener_invoke_ctx ctx = 0;
uint8* outBufs = 0;
int outBufsLen = 0, outBufsCapacity = 0;
uint8* inBufs = 0;
int inBufsLen = 0, inBufsLenReq = 0;
int result = -1;
adsp_listener_remote_handle handle = -1;
uint32 sc = 0;
const char* eheap = getenv("ADSP_LISTENER_HEAP_ID");
int heapid = eheap == 0 ? -1 : atoi(eheap);
const char* eflags = getenv("ADSP_LISTENER_HEAP_FLAGS");
uint32 flags = eflags == 0 ? 0 : (uint32)atoi(eflags);
const char* emin = getenv("ADSP_LISTENER_MEM_CACHE_SIZE");
int cache_size = emin == 0 ? 0 : atoi(emin);
remote_arg args[512];
struct sbuf buf;
eventfd_t event = 0xff;
memset(args, 0, sizeof(args));
set_thread_context((int)(me - &linfo[0]));
if(eheap || eflags || emin) {
FARF(HIGH, "listener using ion heap: %d flags: %x cache: %lld\n", (int)heapid, (int)flags, cache_size);
}
do {
invoke:
sc = 0xffffffff;
if(result != 0) {
outBufsLen = 0;
}
FARF(HIGH, "responding message for %x %x %x %x", ctx, handle, sc, result);
nErr = __QAIC_HEADER(adsp_listener_next2)(
ctx, result, outBufs, outBufsLen,
&ctx, &handle, &sc, inBufs, inBufsLen, &inBufsLenReq);
FARF(HIGH, "got message for %x %x %x %x", ctx, handle, sc, nErr);
if(nErr) {
VERIFY_EPRINTF("listener protocol failure %x\n", nErr);
if (nErr == AEE_EINTERRUPTED) {
goto invoke;
}
VERIFY(0 == (nErr = __QAIC_HEADER(adsp_listener_next2)(
ctx, nErr, 0, 0,
&ctx, &handle, &sc, inBufs, inBufsLen,
&inBufsLenReq)));
}
if(ALIGNB(inBufsLenReq * 2) < inBufsLen && inBufsLen > cache_size) {
void* buf;
int size = ALIGNB(inBufsLenReq * 2);
if(NULL == (buf = rpcmem_realloc(heapid, flags, inBufs, inBufsLen, size))) {
result = AEE_ENORPCMEMORY;
FARF(HIGH, "rpcmem_realloc shrink failed");
goto invoke;
}
inBufs = buf;
inBufsLen = size;
}
if(inBufsLenReq > inBufsLen) {
void* buf;
int req;
int oldLen = inBufsLen;
int size = _SBUF_ALIGN(inBufsLenReq, MIN_BUF_SIZE);
if(AEE_SUCCESS == (buf = rpcmem_realloc(heapid, flags, inBufs, inBufsLen, size))) {
result = AEE_ENORPCMEMORY;
FARF(ERROR, "rpcmem_realloc failed");
goto invoke;
}
inBufs = buf;
inBufsLen = size;
if(0 != (result = __QAIC_HEADER(adsp_listener_get_in_bufs2)(ctx, oldLen,
inBufs + oldLen,
inBufsLen - oldLen, &req))) {
FARF(HIGH, "adsp_listener_invoke_get_in_bufs2 failed %x", result);
goto invoke;
}
if(req > inBufsLen) {
result = AEE_EBADSIZE;
FARF(HIGH, "adsp_listener_invoke_get_in_bufs2 failed %x", result);
goto invoke;
}
}
if(REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc) > 0) {
result = AEE_EINVARGS;
goto invoke;
}
sbuf_init(&buf, 0, inBufs, inBufsLen);
unpack_in_bufs(&buf, args, REMOTE_SCALARS_INBUFS(sc));
unpack_out_lens(&buf, args + REMOTE_SCALARS_INBUFS(sc), REMOTE_SCALARS_OUTBUFS(sc));
sbuf_init(&buf, 0, 0, 0);
pack_out_bufs(&buf, args + REMOTE_SCALARS_INBUFS(sc), REMOTE_SCALARS_OUTBUFS(sc));
outBufsLen = sbuf_needed(&buf);
if(ALIGNB(outBufsLen*2) < outBufsCapacity && outBufsCapacity > cache_size) {
void* buf;
int size = ALIGNB(outBufsLen*2);
if(NULL == (buf = rpcmem_realloc(heapid, flags, outBufs, outBufsCapacity, size))) {
result = AEE_ENORPCMEMORY;
FARF(HIGH, "listener rpcmem_realloc shrink failed");
goto invoke;
}
outBufs = buf;
outBufsCapacity = size;
}
if(outBufsLen > outBufsCapacity) {
void* buf;
int size = ALIGNB(outBufsLen);
if(NULL == (buf = rpcmem_realloc(heapid, flags, outBufs, outBufsCapacity, size))) {
result = AEE_ENORPCMEMORY;
FARF(ERROR, "listener rpcmem_realloc failed");
goto invoke;
}
outBufs = buf;
outBufsLen = size;
outBufsCapacity = size;
}
sbuf_init(&buf, 0, outBufs, outBufsLen);
pack_out_bufs(&buf, args + REMOTE_SCALARS_INBUFS(sc), REMOTE_SCALARS_OUTBUFS(sc));
result = mod_table_invoke(handle, sc, args);
} while(1);
bail:
RPC_FREEIF(heapid, outBufs);
RPC_FREEIF(heapid, inBufs);
if(nErr != AEE_SUCCESS) {
VERIFY_EPRINTF("Error %x: listener thread exited", nErr);
}
eventfd_write(me->eventfd, event);
dlerror();
return (void*)(uintptr_t)nErr;
}
static int listener_start_thread2(struct listener* me) {
return pthread_create(&me->thread, 0, listener2, (void*)me);
}
extern int apps_remotectl_skel_invoke(uint32 _sc, remote_arg* _pra);
extern int apps_std_skel_invoke(uint32 _sc, remote_arg* _pra);
extern int apps_mem_skel_invoke(uint32 _sc, remote_arg* _pra);
extern int adspmsgd_apps_skel_invoke(uint32_t _sc, remote_arg* _pra);
#include "adsp_listener_stub.c"
PL_DEP(mod_table)
PL_DEP(apps_std);
void listener_android_deinit(void) {
PL_DEINIT(mod_table);
PL_DEINIT(apps_std);
}
int listener_android_init(void) {
int nErr = 0;
VERIFY(AEE_SUCCESS == (nErr = PL_INIT(mod_table)));
VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std)));
VERIFY(AEE_SUCCESS == (nErr = mod_table_register_const_handle(0, "apps_remotectl", apps_remotectl_skel_invoke)));
VERIFY(AEE_SUCCESS == (nErr = mod_table_register_static("apps_std", apps_std_skel_invoke)));
VERIFY(AEE_SUCCESS == (nErr = mod_table_register_static("apps_mem", apps_mem_skel_invoke)));
VERIFY(AEE_SUCCESS == (nErr = mod_table_register_static("adspmsgd_apps", adspmsgd_apps_skel_invoke)));
bail:
if(nErr != AEE_SUCCESS) {
listener_android_deinit();
VERIFY_EPRINTF("Error %x: fastrpc listener initialization error", nErr);
}
return nErr;
}
void listener_android_domain_deinit(int domain) {
struct listener* me = &linfo[domain];
FARF(HIGH, "fastrpc listener joining to exit");
if(me->thread) {
pthread_join(me->thread, 0);
me->thread = 0;
}
FARF(HIGH, "fastrpc listener joined");
if(me->eventfd != -1) {
close(me->eventfd);
me->eventfd = -1;
}
}
int listener_android_domain_init(int domain) {
struct listener* me = &linfo[domain];
int nErr = 0;
VERIFYC(-1 != (me->eventfd = eventfd(0, 0)), AEE_EINVALIDFD);
nErr = __QAIC_HEADER(adsp_listener_init2)();
if(AEE_EUNSUPPORTEDAPI == nErr) {
FARF(HIGH, "listener2 initialization error falling back to listener1 %x", nErr);
VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_init)()));
VERIFY(AEE_SUCCESS == (nErr = listener_start_thread(me)));
} else if(AEE_SUCCESS == nErr) {
FARF(HIGH, "listener2 initialized for domain %d", domain);
VERIFY(AEE_SUCCESS == (nErr = listener_start_thread2(me)));
}
bail:
if(nErr != AEE_SUCCESS) {
VERIFY_EPRINTF("Error %x: listener android domain init failed. domain %d\n", nErr, domain);
listener_android_domain_deinit(domain);
}
return nErr;
}
int listener_android_geteventfd(int domain, int *fd) {
struct listener* me = &linfo[domain];
int nErr = 0;
VERIFYC(-1 != me->eventfd, AEE_EINVALIDFD);
*fd = me->eventfd;
bail:
if (nErr != AEE_SUCCESS) {
VERIFY_EPRINTF("Error %x: listener android getevent file descriptor failed for domain %d\n", nErr, domain);
}
return nErr;
}
PL_DEFINE(listener_android, listener_android_init, listener_android_deinit)