diff options
Diffstat (limited to 'src')
43 files changed, 16973 insertions, 0 deletions
diff --git a/src/AEEsmath.h b/src/AEEsmath.h new file mode 100644 index 0000000..1acac47 --- /dev/null +++ b/src/AEEsmath.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/*====================================================================== + +DESCRIPTION: Safe math library; implements saturating add. + +====================================================================*/ + +extern int smath_Add(int a, int b); +extern int smath_Sub(int a, int b); +extern int smath_Mul(int a, int b); diff --git a/src/BufBound.c b/src/BufBound.c new file mode 100644 index 0000000..e9e64e3 --- /dev/null +++ b/src/BufBound.c @@ -0,0 +1,225 @@ +/* + * 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. + */ +/*============================================================================== + +FILE: AEEBufBound.c + +SERVICES: + AEEBufBound APIs + +GENERAL DESCRIPTION: + AEEBufBound provides a "bounded buffer" API that facilitates + measuring strings or character output. It's design accomodates + the implementation of functions that can have the same exact logic + for measuring and outputting char buffer content. + +REVISION HISTORY: + Sun Mar 06 11:23:10 2005 Created + +==============================================================================*/ +#include <limits.h> +#include "AEEBufBound.h" +#include "AEEstd.h" + +// Note on bounds-checking logic and saturation: +// +// Simple pointer comparisons are not adequate for bounds checking. pcBuf +// and pcEnd are assumed to be valid pointers in the address space. But +// pcWrite is not ... it is a theoretical value that can exceed pcEnd, and +// may in fact wrap around the end of the address space. In that case the +// test for (pcWrite < pcEnd) will yield TRUE, although pcWrite is outside +// the buffer. Use (pcEnd-pcWrite) > 0 to be accurate. +// +// In order to ensure this works in all cases, we need to avoid integer +// overflows. We do this by restricting pcWrite to the range +// [pcBuf..pcBuf+INT_MAX]. The ensures that pcWrite-pcBuf and pcWrite-pcBuf +// will always be valid integers. It also allows us to ensure that +// BufBound_Wrote() will not return wildly misleading results. +// +// PCSAT +// pcBuf pcEnd pcBuf+MAXINT +// |-------------------| . . . . . . . . . | +// ^ ^ +// pcWrite: (a) (b) +// + +#define PCSAT(me) ((me)->pcBuf + INT_MAX) + + +// Advance me->pcWrite, saturating. +// +// On entry: +// *pnLen = number of bytes to be written (non-negative) +// On exit: +// return value = where to write (pointer into the buffer) +// *pnLen = number of bytes to write +// +static char * +BufBound_ValidateWrite(BufBound *me, int *pnLen) +{ + int nLen = *pnLen; + char *pcWrite = me->pcWrite; + int nMaxCopy = me->pcEnd - pcWrite; // could be negative! + + if ( nMaxCopy < nLen ) { + // Must check PCSAT to validate advance + int nMaxAdvance = PCSAT(me) - pcWrite; // max amount to advance + + if (nLen > nMaxAdvance) { + nLen = nMaxAdvance; + } + if (nMaxCopy < 0) { + nMaxCopy = 0; + } + } else { + // Simple case: all fits in the buffer + nMaxCopy = nLen; + } + + *pnLen = nMaxCopy; + me->pcWrite = pcWrite + nLen; + return pcWrite; +} + +void BufBound_Write(BufBound *me, const char *pc, int nLen) +{ + if (nLen > 0) { + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + while (--nLen >= 0) { + pcDest[nLen] = pc[nLen]; + } + } +} + +void BufBound_Putnc(BufBound *me, char c, int nLen) +{ + if (nLen > 0) { + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + while (--nLen >= 0) { + pcDest[nLen] = c; + } + } +} + +void BufBound_Advance(BufBound *me, int nLen) +{ + uint32 uOffset = (uint32)((me->pcWrite - me->pcBuf) + nLen); + + if (uOffset > INT_MAX) { + uOffset = INT_MAX; + if (nLen < 0) { + uOffset = 0; + } + } + me->pcWrite = me->pcBuf + uOffset; +} + +void BufBound_Init(BufBound *me, char *pBuf, int nLen) +{ + if (nLen < 0) { + nLen = 0; + } + me->pcWrite = me->pcBuf = pBuf; + me->pcEnd = pBuf + nLen; +} + +void BufBound_Putc(BufBound *me, char c) +{ + if ( (me->pcEnd - me->pcWrite) > 0) { + *me->pcWrite++ = c; + } else if (me->pcWrite != PCSAT(me)) { + ++me->pcWrite; + } +} + +void BufBound_ForceNullTerm(BufBound *me) +{ + if ( (me->pcEnd - me->pcWrite) > 0) { + *me->pcWrite++ = '\0'; + } else { + if (me->pcWrite != PCSAT(me)) { + ++me->pcWrite; + } + // ensure null termination if non-empty buffer + if (me->pcEnd != me->pcBuf) { + me->pcEnd[-1] = '\0'; + } + } +} + +void BufBound_Puts(BufBound *me, const char* cpsz) +{ + BufBound_Write(me, cpsz, std_strlen(cpsz)); +} + +int BufBound_BufSize(BufBound* me) +{ + return me->pcEnd - me->pcBuf; +} + +int BufBound_Left(BufBound* me) +{ + return (me->pcEnd - me->pcWrite); +} + +int BufBound_ReallyWrote(BufBound* me) +{ + return STD_MIN(me->pcEnd - me->pcBuf, me->pcWrite - me->pcBuf); +} + +int BufBound_Wrote(BufBound* me) +{ + return (me->pcWrite - me->pcBuf); +} + +void BufBound_WriteLE(BufBound *me, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + if (nSrcSize > 0) { + int nLen = nSrcSize; + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + (void)std_CopyLE(pcDest, nLen, pvSrc, nSrcSize, pszFields); + } +} + +void BufBound_WriteBE(BufBound *me, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + if (nSrcSize > 0) { + int nLen = nSrcSize; + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + (void)std_CopyBE(pcDest, nLen, pvSrc, nSrcSize, pszFields); + } +} diff --git a/src/adsp_current_process1_stub.c b/src/adsp_current_process1_stub.c new file mode 100644 index 0000000..cffe9d8 --- /dev/null +++ b/src/adsp_current_process1_stub.c @@ -0,0 +1,587 @@ +#ifndef _ADSP_CURRENT_PROCESS1_STUB_H +#define _ADSP_CURRENT_PROCESS1_STUB_H +/* + * 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 "adsp_current_process1.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#include <string.h> +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_CURRENT_PROCESS1_SLIM_H +#define _ADSP_CURRENT_PROCESS1_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const SequenceType sequenceTypes[1] = {{&(types[0]),0x0,0x4,0x4,0x0}}; +static const Type types[1] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8)}}; +static const Parameter parameters[6] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x2,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x2,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[6] = {(&(parameters[3])),(&(parameters[4])),(&(parameters[0])),(&(parameters[1])),(&(parameters[5])),(&(parameters[2]))}; +static const Method methods[5] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[2])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[5])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,3,2,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x1,0x0,0x0),0x0,0x4,1,1,(&(parameterArrays[4])),0x1,0x4}}; +static const Method* const methodArrays[6] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2]),&(methods[3]),&(methods[4])}; +static const char strings[77] = "set_logging_params\0thread_exit\0filesToLog\0getASID\0close\0asid\0mask\0open\0uri\0h\0"; +static const uint16_t methodStrings[12] = {0,61,31,66,71,75,42,56,50,75,19,26}; +static const uint16_t methodStringsArrays[6] = {3,8,11,10,0,6}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_current_process1_slim) = {6,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_CURRENT_PROCESS1_SLIM_H +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_skel_handle_invoke)(remote_handle64 _h, uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_invoke)(_h, _sc, _pra); +} +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_exit)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_thread_exit)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method(_handle, _mid); +} +static __inline int _stub_unpack(remote_arg* _praROutPost, remote_arg* _ppraROutPost[1], void* _primROut, char* _in0[1], uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +0; + return _nErr; +} +static __inline int _stub_pack(_allocator* _al, remote_arg* _praIn, remote_arg* _ppraIn[1], remote_arg* _praROut, remote_arg* _ppraROut[1], void* _primIn, void* _primROut, char* _in0[1], uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _in0Len[0] = (1 + strlen(_in0[0])); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn[0].buf.pv = _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 1; + _ppraROutStart[0] += (_praROut - _praROutStart) +0; + return _nErr; +} +static __inline void _count(int _numIn[1], int _numROut[1], char* _in0[1], uint32_t _in0Len[1]) { + _numIn[0] += 1; + _numROut[0] += 0; +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, uint16_t _in0[1], void* _in1[1], uint32_t _in1Len[1]) { + remote_arg* _pra; + int _numIn[1]; + int _numROut[1]; + char* _seq_nat1; + int _ii; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]; + remote_arg* _praIn; + remote_arg** _ppraIn = &_praIn; + remote_arg* _praROut; + remote_arg** _ppraROut = &_praROut; + char* _seq_primIn1; + int _nErr = 0; + remote_arg* _praROutPost; + remote_arg** _ppraROutPost = &_praROutPost; + _numIn[0] = 1; + _numROut[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2]))); + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((_numIn[0] + _numROut[0]) + 1) + 0) * sizeof(_pra[0])), 4, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 2); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _ALLOCATE(_nErr, _al, (_in1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), 0, 0), _pra)); + _praROutPost = _praROut; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_set_logging_params)(remote_handle64 _handle, unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_1(_handle, _mid, (uint16_t*)&mask, (void**)&filesToLog, (uint32_t*)&filesToLogLen); +} +static __inline int _stub_method_2(remote_handle64 _handle, uint32_t _mid, uint32_t _rout0[1]) { + int _numIn[1]; + remote_arg _pra[1]; + uint32_t _primROut[1]; + int _nErr = 0; + _numIn[0] = 0; + _pra[(_numIn[0] + 0)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 0)].buf.nLen = sizeof(_primROut); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 1, 0, 0), _pra)); + _COPY(_rout0, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_getASID)(remote_handle64 _handle, unsigned int* asid) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + return _stub_method_2(_handle, _mid, (uint32_t*)asid); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS1_STUB_H diff --git a/src/adsp_current_process_stub.c b/src/adsp_current_process_stub.c new file mode 100644 index 0000000..32c3047 --- /dev/null +++ b/src/adsp_current_process_stub.c @@ -0,0 +1,669 @@ +#ifndef _ADSP_CURRENT_PROCESS_STUB_H +#define _ADSP_CURRENT_PROCESS_STUB_H +/* + * 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 "adsp_current_process.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#include <string.h> +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type *seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_CURRENT_PROCESS_SLIM_H +#define _ADSP_CURRENT_PROCESS_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const SequenceType sequenceTypes[1] = {{&(types[0]),0x0,0x4,0x4,0x0}}; +static const Type types[1] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8)}}; +static const Parameter parameters[3] = {{0x2,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x2,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[3] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[3] = {{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,3,2,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x1,0x0,0x0),0x0,0x4,1,1,(&(parameterArrays[2])),0x1,0x4}}; +static const Method* const methodArrays[4] = {&(methods[0]),&(methods[0]),&(methods[1]),&(methods[2])}; +static const char strings[60] = "set_logging_params\0thread_exit\0filesToLog\0getASID\0asid\0mask\0"; +static const uint16_t methodStrings[7] = {0,55,31,42,50,19,26}; +static const uint16_t methodStringsArrays[4] = {6,5,0,3}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_current_process_slim) = {4,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_CURRENT_PROCESS_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_current_process_handle +#define _const_adsp_current_process_handle ((remote_handle)-1) +#endif //_const_adsp_current_process_handle + +static void _adsp_current_process_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_current_process_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_current_process_handle; + } +} + +static int _adsp_current_process_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_current_process_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_current_process_handle(void) { + remote_handle* ph; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_current_process_handle, 0, sizeof(*ph), _adsp_current_process_pls_ctor, "adsp_current_process", _adsp_current_process_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_current_process_handle, 0, sizeof(*ph), _adsp_current_process_pls_ctor, "adsp_current_process", _adsp_current_process_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_current_process_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#include "Windows.h" +uint32_t _adsp_current_process_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_current_process_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_current_process_handle(void) { + static remote_handle handle = _const_adsp_current_process_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_current_process_pls_ctor("adsp_current_process", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_current_process_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_current_process_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle_invoke)(_adsp_current_process_handle(), _sc, _pra); +} + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_exit)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + return _stub_method(_adsp_current_process_handle(), _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_thread_exit)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + return _stub_method(_adsp_current_process_handle(), _mid); +} +static __inline int _stub_unpack(remote_arg* _praROutPost, remote_arg* _ppraROutPost[1], void* _primROut, char* _in0[1], uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +0; + return _nErr; +} +static __inline int _stub_pack(_allocator* _al, remote_arg* _praIn, remote_arg* _ppraIn[1], remote_arg* _praROut, remote_arg* _ppraROut[1], void* _primIn, void* _primROut, char* _in0[1], uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _in0Len[0] = (1 + strlen(_in0[0])); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn[0].buf.pv = _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 1; + _ppraROutStart[0] += (_praROut - _praROutStart) +0; + return _nErr; +} +static __inline void _count(int _numIn[1], int _numROut[1], char* _in0[1], uint32_t _in0Len[1]) { + _numIn[0] += 1; + _numROut[0] += 0; +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, uint16_t _in0[1], void* _in1[1], uint32_t _in1Len[1]) { + remote_arg* _pra; + int _numIn[1]; + int _numROut[1]; + char* _seq_nat1; + int _ii; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]; + remote_arg* _praIn; + remote_arg** _ppraIn = &_praIn; + remote_arg* _praROut; + remote_arg** _ppraROut = &_praROut; + char* _seq_primIn1; + int _nErr = 0; + remote_arg* _praROutPost; + remote_arg** _ppraROutPost = &_praROutPost; + _numIn[0] = 1; + _numROut[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2]))); + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((_numIn[0] + _numROut[0]) + 1) + 0) * sizeof(_pra[0])), 4, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 2); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _ALLOCATE(_nErr, _al, (_in1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), 0, 0), _pra)); + _praROutPost = _praROut; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_set_logging_params)(unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method_1(_adsp_current_process_handle(), _mid, (uint16_t*)&mask, (void**)&filesToLog, (uint32_t*)&filesToLogLen); +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid, uint32_t _rout0[1]) { + int _numIn[1]; + remote_arg _pra[1]; + uint32_t _primROut[1]; + int _nErr = 0; + _numIn[0] = 0; + _pra[(_numIn[0] + 0)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 0)].buf.nLen = sizeof(_primROut); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 1, 0, 0), _pra)); + _COPY(_rout0, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_getASID)(unsigned int* asid) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_2(_adsp_current_process_handle(), _mid, (uint32_t*)asid); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS_STUB_H diff --git a/src/adsp_def_symbols.lst b/src/adsp_def_symbols.lst new file mode 100644 index 0000000..f998107 --- /dev/null +++ b/src/adsp_def_symbols.lst @@ -0,0 +1,33 @@ +/* + * 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. + */ +ADSPRPC { + global: + adsp_default_listener_start; + local: *; +}; diff --git a/src/adsp_default_listener.c b/src/adsp_default_listener.c new file mode 100644 index 0000000..5f1cb80 --- /dev/null +++ b/src/adsp_default_listener.c @@ -0,0 +1,106 @@ +/* + * 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. + */ +//#ifndef VERIFY_PRINT_ERROR +//#define VERIFY_PRINT_ERROR +//#endif + +#define FARF_ERROR 1 + +#include <stdio.h> +#include <stdlib.h> +#include <poll.h> +#include <unistd.h> +#include <sys/eventfd.h> +#include <string.h> +#include "adsp_default_listener.h" +#include "AEEStdErr.h" +#include "verify.h" +#include "remote.h" +#include "HAP_farf.h" +#include "adspmsgd_adsp.h" + +int adsp_default_listener_start(int argc, char* argv[]) { + struct pollfd pfd; + eventfd_t event = 0; + remote_handle fd; + int nErr = AEE_SUCCESS; + char *name = NULL; + int namelen = 0; + (void)argc; + (void)argv; + if (argc > 1) { + namelen = strlen(ITRANSPORT_PREFIX "createstaticpd:") + strlen(argv[1]); + name = (char *)malloc((namelen + 1) * sizeof(char)); + VERIFYC(NULL != name, AEE_ENOMEMORY); + std_strlcpy(name, ITRANSPORT_PREFIX "createstaticpd:", strlen(ITRANSPORT_PREFIX "createstaticpd:")+1); + std_strlcat(name, argv[1], namelen+1); + } else { + namelen = strlen(ITRANSPORT_PREFIX "attachguestos"); + name = (char *)malloc((namelen + 1) * sizeof(char)); + VERIFYC(NULL != name, AEE_ENOMEMORY); + std_strlcpy(name, ITRANSPORT_PREFIX "attachguestos", strlen(ITRANSPORT_PREFIX "attachguestos")+1); + } + VERIFY_EPRINTF("adsp_default_listener_start started\n"); + VERIFYC(!setenv("ADSP_LISTENER_MEM_CACHE_SIZE", "1048576", 0), AEE_ESETENV); + VERIFY(0 == (nErr = remote_handle_open(name, &fd))); + VERIFY(0 == (nErr = adsp_default_listener_register())); + VERIFY(0 == (nErr = remote_handle_open(ITRANSPORT_PREFIX "geteventfd", + (remote_handle*)&pfd.fd))); + free(name); + name = NULL; + pfd.events = POLLIN; + pfd.revents = 0; +#ifdef PD_EXCEPTION_LOGGING + +if(argc == 1){ + adspmsgd_adsp_init2(); +} + +#endif + while (1) { + VERIFYC(0 < poll(&pfd, 1, -1), AEE_EPOLL); + VERIFYC(0 == eventfd_read(pfd.fd, &event), AEE_EEVENTREAD); + if (event) { + break; + } + } +bail: +#ifdef PD_EXCEPTION_LOGGING +if(argc == 1) + adspmsgd_adsp_deinit(); +#endif + if(nErr != AEE_SUCCESS) { + if(name != NULL){ + free(name); + name = NULL; + } + //FARF(ERROR, "Error %x, adsp_default_listener_start exiting\n", nErr); + } + return nErr; +} diff --git a/src/adsp_default_listener_stub.c b/src/adsp_default_listener_stub.c new file mode 100644 index 0000000..c2c0057 --- /dev/null +++ b/src/adsp_default_listener_stub.c @@ -0,0 +1,517 @@ +/* + * 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. + */ +#ifndef _ADSP_DEFAULT_LISTENER_STUB_H +#define _ADSP_DEFAULT_LISTENER_STUB_H +#include "adsp_default_listener.h" +#include "remote.h" +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} allocator; + +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + + +static __inline int allocator_alloc(allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + + +static __inline void allocator_deinit(allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +static __inline void allocator_init(allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_DEFAULT_LISTENER_SLIM_H +#define _ADSP_DEFAULT_LISTENER_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Method methods[1] = {{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[1] = {&(methods[0])}; +static const char strings[9] = "register\0"; +static const uint16_t methodStrings[1] = {0}; +static const uint16_t methodStringsArrays[1] = {0}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_default_listener_slim) = {1,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_DEFAULT_LISTENER_SLIM_H +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE_LINE__ ": error: %d\n", (int)(ee)));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_default_listener_handle +#define _const_adsp_default_listener_handle ((remote_handle)-1) +#endif //_const_adsp_default_listener_handle + +static void _adsp_default_listener_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_default_listener_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_default_listener_handle; + } +} + +static int _adsp_default_listener_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_default_listener_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_default_listener_handle(void) { + remote_handle* ph; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_default_listener_handle, 0, sizeof(*ph), _adsp_default_listener_pls_ctor, "adsp_default_listener", _adsp_default_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_default_listener_handle, 0, sizeof(*ph), _adsp_default_listener_pls_ctor, "adsp_default_listener", _adsp_default_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_default_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#include "Windows.h" +uint32_t _adsp_default_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_default_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_default_listener_handle(void) { + static remote_handle handle = _const_adsp_default_listener_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_default_listener_pls_ctor("adsp_default_listener", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_default_listener_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_default_listener_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_default_listener_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle_invoke)(_adsp_default_listener_handle(), _sc, _pra); +} + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_default_listener_register)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + return _stub_method(_adsp_default_listener_handle(), _mid); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_DEFAULT_LISTENER_STUB_H diff --git a/src/adsp_listener_stub.c b/src/adsp_listener_stub.c new file mode 100644 index 0000000..f94e2c4 --- /dev/null +++ b/src/adsp_listener_stub.c @@ -0,0 +1,797 @@ +/* + * 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. + */ +#ifndef _ADSP_LISTENER_STUB_H +#define _ADSP_LISTENER_STUB_H +#include "adsp_listener.h" +#include "remote.h" +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} allocator; + +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + + +static __inline int allocator_alloc(allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + + +static __inline void allocator_deinit(allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +static __inline void allocator_init(allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_LISTENER_SLIM_H +#define _ADSP_LISTENER_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[3]; +static const SequenceType sequenceTypes[1] = {{&(types[0]),0x0,0x4,0x4,0x0}}; +static const Type types[3] = {{0x8,{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,0x4},{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4}}; +static const Parameter parameters[9] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x8,{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,3,0},{0x8,{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,0x4,3,0},{0x8,{{(const uintptr_t)&(types[2]),(const uintptr_t)0x0}}, 9,0x4,3,0},{0x8,{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,0x4,0,0},{0x8,{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[23] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[3])),(&(parameters[3])),(&(parameters[3])),(&(parameters[4])),(&(parameters[5])),(&(parameters[5])),(&(parameters[0])),(&(parameters[1])),(&(parameters[6])),(&(parameters[3])),(&(parameters[3])),(&(parameters[3])),(&(parameters[7])),(&(parameters[8])),(&(parameters[0])),(&(parameters[1])),(&(parameters[7])),(&(parameters[8])),(&(parameters[0])),(&(parameters[4]))}; +static const Method methods[5] = {{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x18,0xc,16,9,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,4,2,(&(parameterArrays[21])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x10,0x10,11,8,(&(parameterArrays[9])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0xc,0x4,6,4,(&(parameterArrays[17])),0x4,0x4}}; +static const Method* const methodArrays[6] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2]),&(methods[3]),&(methods[4])}; +static const char strings[165] = "invoke_get_in_bufs\0routBufLenReq\0get_in_bufs2\0inBufLenReq\0next_invoke\0bufsLenReq\0prevResult\0inBuffers\0prevbufs\0outBufs\0prevCtx\0offset\0handle\0next2\0init2\0init\0ctx\0sc\0"; +static const uint16_t methodStrings[29] = {58,119,81,111,158,134,162,92,46,19,141,119,81,102,158,134,162,14,70,33,158,127,14,70,0,158,92,147,153}; +static const uint16_t methodStringsArrays[6] = {0,24,28,27,10,19}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_listener_slim) = {6,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_LISTENER_SLIM_H +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE_LINE__ ": error: %d\n", (int)(ee)));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_listener_handle +#define _const_adsp_listener_handle ((remote_handle)-1) +#endif //_const_adsp_listener_handle + +static void _adsp_listener_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_listener_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_listener_handle; + } +} + +static int _adsp_listener_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_listener_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_listener_handle(void) { + remote_handle* ph; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_listener_handle, 0, sizeof(*ph), _adsp_listener_pls_ctor, "adsp_listener", _adsp_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_listener_handle, 0, sizeof(*ph), _adsp_listener_pls_ctor, "adsp_listener", _adsp_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#include "Windows.h" +uint32_t _adsp_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_listener_handle(void) { + static remote_handle handle = _const_adsp_listener_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_listener_pls_ctor("adsp_listener", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_listener_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_listener_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle_invoke)(_adsp_listener_handle(), _sc, _pra); +} + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_unpack(remote_arg* _praROutPost, remote_arg* _ppraROutPost[1], void* _primROut, char* _rout0[1], uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _stub_unpack_1(remote_arg* _praROutPost, remote_arg* _ppraROutPost[1], void* _primROut, char* _in0[1], uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +0; + return _nErr; +} +static __inline int _stub_pack(allocator* _al, remote_arg* _praIn, remote_arg* _ppraIn[1], remote_arg* _praROut, remote_arg* _ppraROut[1], void* _primIn, void* _primROut, char* _rout0[1], uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + return _nErr; +} +static __inline int _stub_pack_1(allocator* _al, remote_arg* _praIn, remote_arg* _ppraIn[1], remote_arg* _praROut, remote_arg* _ppraROut[1], void* _primIn, void* _primROut, char* _in0[1], uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn[0].buf.pv = _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 1; + _ppraROutStart[0] += (_praROut - _praROutStart) +0; + return _nErr; +} +static __inline void _count(int _numIn[1], int _numROut[1], char* _rout0[1], uint32_t _rout0Len[1]) { + _numIn[0] += 0; + _numROut[0] += 1; +} +static __inline void _count_1(int _numIn[1], int _numROut[1], char* _in0[1], uint32_t _in0Len[1]) { + _numIn[0] += 1; + _numROut[0] += 0; +} +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], void* _in2[1], uint32_t _in2Len[1], uint32_t _rout3[1], uint32_t _rout4[1], uint32_t _rout5[1], void* _rout6[1], uint32_t _rout6Len[1], char* _rout7[1], uint32_t _rout7Len[1], char* _rout8[1], uint32_t _rout8Len[1]) { + remote_arg* _pra; + int _numIn[1]; + int _numROut[1]; + char* _seq_nat2; + int _ii; + char* _seq_nat6; + allocator _al[1] = {{0}}; + uint32_t _primIn[6]; + uint32_t _primROut[3]; + remote_arg* _praIn; + remote_arg* _praROut; + remote_arg* _praROutPost; + remote_arg** _ppraROutPost = &_praROutPost; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + char* _seq_primIn2; + int _nErr = 0; + char* _seq_primIn6; + _numIn[0] = 2; + _numROut[0] = 2; + for(_ii = 0, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + 8)) + { + _count_1(_numIn, _numROut, (char**)&(((uint32_t*)_seq_nat2)[0]), (uint32_t*)&(((uint32_t*)_seq_nat2)[1])); + } + for(_ii = 0, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_nat6 = (_seq_nat6 + 8)) + { + _count(_numIn, _numROut, (char**)&(((uint32_t*)_seq_nat6)[0]), (uint32_t*)&(((uint32_t*)_seq_nat6)[1])); + } + allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((_numIn[0] + _numROut[0]) + 1) + 1) * sizeof(_pra[0])), 4, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROutPost = _praROut; + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2Len, 0, 4); + _ALLOCATE(_nErr, _al, (_in2Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in2Len[0]); + for(_ii = 0, _seq_primIn2 = (char*)_praIn[0].buf.pv, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_primIn2 = (_seq_primIn2 + 4), _seq_nat2 = (_seq_nat2 + 8)) + { + _TRY(_nErr, _stub_pack_1(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _seq_primIn2, 0, (char**)&(((uint32_t*)_seq_nat2)[0]), (uint32_t*)&(((uint32_t*)_seq_nat2)[1]))); + } + _COPY(_primIn, 12, _rout6Len, 0, 4); + _ALLOCATE(_nErr, _al, (_rout6Len[0] * 4), 4, _praIn[1].buf.pv); + _praIn[1].buf.nLen = (4 * _rout6Len[0]); + for(_ii = 0, _seq_primIn6 = (char*)_praIn[1].buf.pv, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_primIn6 = (_seq_primIn6 + 4), _seq_nat6 = (_seq_nat6 + 8)) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 2), _ppraIn, (_praROut + 0), _ppraROut, _seq_primIn6, 0, (char**)&(((uint32_t*)_seq_nat6)[0]), (uint32_t*)&(((uint32_t*)_seq_nat6)[1]))); + } + _COPY(_primIn, 16, _rout7Len, 0, 4); + _praROut[0].buf.pv = _rout7[0]; + _praROut[0].buf.nLen = (4 * _rout7Len[0]); + _COPY(_primIn, 20, _rout8Len, 0, 4); + _praROut[1].buf.pv = _rout8[0]; + _praROut[1].buf.nLen = (4 * _rout8Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 1), 0, 0), _pra)); + for(_ii = 0, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + 8)) + { + _TRY(_nErr, _stub_unpack_1((_praROutPost + 0), _ppraROutPost, 0, (char**)&(((uint32_t*)_seq_nat2)[0]), (uint32_t*)&(((uint32_t*)_seq_nat2)[1]))); + } + _COPY(_rout3, 0, _primROut, 0, 4); + _COPY(_rout4, 0, _primROut, 4, 4); + _COPY(_rout5, 0, _primROut, 8, 4); + for(_ii = 0, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_nat6 = (_seq_nat6 + 8)) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, (char**)&(((uint32_t*)_seq_nat6)[0]), (uint32_t*)&(((uint32_t*)_seq_nat6)[1]))); + } + _CATCH(_nErr) {} + allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_next_invoke)(adsp_listener_invoke_ctx prevCtx, int prevResult, const adsp_listener_buffer* outBufs, int outBufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32* sc, adsp_listener_buffer* inBuffers, int inBuffersLen, int* inBufLenReq, int inBufLenReqLen, int* routBufLenReq, int routBufLenReqLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + return _stub_method(_adsp_listener_handle(), _mid, (uint32_t*)&prevCtx, (uint32_t*)&prevResult, (void**)&outBufs, (uint32_t*)&outBufsLen, (uint32_t*)ctx, (uint32_t*)handle, (uint32_t*)sc, (void**)&inBuffers, (uint32_t*)&inBuffersLen, (char**)&inBufLenReq, (uint32_t*)&inBufLenReqLen, (char**)&routBufLenReq, (uint32_t*)&routBufLenReqLen); +} +static __inline int _stub_unpack_2(remote_arg* _praROutPost, remote_arg* _ppraROutPost[1], void* _primROut, char* _rout0[1], uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _stub_pack_2(allocator* _al, remote_arg* _praIn, remote_arg* _ppraIn[1], remote_arg* _praROut, remote_arg* _ppraROut[1], void* _primIn, void* _primROut, char* _rout0[1], uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + return _nErr; +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], void* _rout1[1], uint32_t _rout1Len[1]) { + remote_arg* _pra; + int _numIn[1]; + int _numROut[1]; + char* _seq_nat1; + int _ii; + allocator _al[1] = {{0}}; + uint32_t _primIn[2]; + remote_arg* _praIn; + remote_arg* _praROut; + remote_arg* _praROutPost; + remote_arg** _ppraROutPost = &_praROutPost; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + char* _seq_primIn1; + int _nErr = 0; + _numIn[0] = 1; + _numROut[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + 8)) + { + _count(_numIn, _numROut, (char**)&(((uint32_t*)_seq_nat1)[0]), (uint32_t*)&(((uint32_t*)_seq_nat1)[1])); + } + allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((_numIn[0] + _numROut[0]) + 1) + 0) * sizeof(_pra[0])), 4, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _praROutPost = _praROut; + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _rout1Len, 0, 4); + _ALLOCATE(_nErr, _al, (_rout1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _rout1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + 8)) + { + _TRY(_nErr, _stub_pack_2(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _seq_primIn1, 0, (char**)&(((uint32_t*)_seq_nat1)[0]), (uint32_t*)&(((uint32_t*)_seq_nat1)[1]))); + } + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), 0, 0), _pra)); + for(_ii = 0, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + 8)) + { + _TRY(_nErr, _stub_unpack_2((_praROutPost + 0), _ppraROutPost, 0, (char**)&(((uint32_t*)_seq_nat1)[0]), (uint32_t*)&(((uint32_t*)_seq_nat1)[1]))); + } + _CATCH(_nErr) {} + allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_invoke_get_in_bufs)(adsp_listener_invoke_ctx ctx, adsp_listener_buffer* inBuffers, int inBuffersLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + return _stub_method_1(_adsp_listener_handle(), _mid, (uint32_t*)&ctx, (void**)&inBuffers, (uint32_t*)&inBuffersLen); +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_init)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method_2(_adsp_listener_handle(), _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_init2)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_2(_adsp_listener_handle(), _mid); +} +static __inline int _stub_method_3(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], char* _in2[1], uint32_t _in2Len[1], uint32_t _rout3[1], uint32_t _rout4[1], uint32_t _rout5[1], char* _rout6[1], uint32_t _rout6Len[1], uint32_t _rout7[1]) { + int _numIn[1]; + remote_arg _pra[4]; + uint32_t _primIn[4]; + uint32_t _primROut[4]; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _numIn[0] = 1; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = _in2[0]; + _praIn[0].buf.nLen = (1 * _in2Len[0]); + _COPY(_primIn, 12, _rout6Len, 0, 4); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout6[0]; + _praROut[0].buf.nLen = (1 * _rout6Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _pra)); + _COPY(_rout3, 0, _primROut, 0, 4); + _COPY(_rout4, 0, _primROut, 4, 4); + _COPY(_rout5, 0, _primROut, 8, 4); + _COPY(_rout7, 0, _primROut, 12, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_next2)(adsp_listener_invoke_ctx prevCtx, int prevResult, const uint8* prevbufs, int prevbufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32* sc, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_3(_adsp_listener_handle(), _mid, (uint32_t*)&prevCtx, (uint32_t*)&prevResult, (char**)&prevbufs, (uint32_t*)&prevbufsLen, (uint32_t*)ctx, (uint32_t*)handle, (uint32_t*)sc, (char**)&bufs, (uint32_t*)&bufsLen, (uint32_t*)bufsLenReq); +} +static __inline int _stub_method_4(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], char* _rout2[1], uint32_t _rout2Len[1], uint32_t _rout3[1]) { + int _numIn[1]; + remote_arg _pra[3]; + uint32_t _primIn[3]; + uint32_t _primROut[1]; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _rout2Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout2[0]; + _praROut[0].buf.nLen = (1 * _rout2Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout3, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_get_in_bufs2)(adsp_listener_invoke_ctx ctx, int offset, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + return _stub_method_4(_adsp_listener_handle(), _mid, (uint32_t*)&ctx, (uint32_t*)&offset, (char**)&bufs, (uint32_t*)&bufsLen, (uint32_t*)bufsLenReq); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_LISTENER_STUB_H diff --git a/src/adsp_perf_stub.c b/src/adsp_perf_stub.c new file mode 100644 index 0000000..46ecc78 --- /dev/null +++ b/src/adsp_perf_stub.c @@ -0,0 +1,623 @@ +/* + * 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. + */ +#ifndef _ADSP_PERF_STUB_H +#define _ADSP_PERF_STUB_H +#include "adsp_perf.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_PERF_SLIM_H +#define _ADSP_PERF_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[2]; +static const Type types[2] = {{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8},{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1}}; +static const Parameter parameters[4] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[5] = {(&(parameters[2])),(&(parameters[3])),(&(parameters[3])),(&(parameters[1])),(&(parameters[0]))}; +static const Method methods[3] = {{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[4])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x0,3,1,(&(parameterArrays[3])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x4,0x8,5,3,(&(parameterArrays[0])),0x4,0x4}}; +static const Method* const methodArrays[3] = {&(methods[0]),&(methods[1]),&(methods[2])}; +static const char strings[48] = "get_usecs\0get_keys\0numKeys\0maxLen\0enable\0dst\0ix\0"; +static const uint16_t methodStrings[8] = {10,14,27,19,0,41,34,45}; +static const uint16_t methodStringsArrays[3] = {6,4,0}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_perf_slim) = {3,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_PERF_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_perf_handle +#define _const_adsp_perf_handle ((remote_handle)-1) +#endif //_const_adsp_perf_handle + +static void _adsp_perf_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_perf_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_perf_handle; + } +} + +static int _adsp_perf_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_perf_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_perf_handle(void) { + remote_handle* ph; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_perf_handle, 0, sizeof(*ph), _adsp_perf_pls_ctor, "adsp_perf", _adsp_perf_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_perf_handle, 0, sizeof(*ph), _adsp_perf_pls_ctor, "adsp_perf", _adsp_perf_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_perf_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#include "Windows.h" +uint32_t _adsp_perf_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_perf_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_perf_handle(void) { + static remote_handle handle = _const_adsp_perf_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_perf_pls_ctor("adsp_perf", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_perf_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_perf_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle_invoke)(_adsp_perf_handle(), _sc, _pra); +} + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, uint32_t _in0[1]) { + remote_arg _pra[1]; + uint32_t _primIn[1]; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf_enable)(int ix) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + return _stub_method(_adsp_perf_handle(), _mid, (uint32_t*)&ix); +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, char* _rout0[1], uint32_t _rout0Len[1]) { + int _numIn[1]; + remote_arg _pra[2]; + uint32_t _primIn[1]; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (8 * _rout0Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf_get_usecs)(int64* dst, int dstLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + return _stub_method_1(_adsp_perf_handle(), _mid, (char**)&dst, (uint32_t*)&dstLen); +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid, char* _rout0[1], uint32_t _rout0Len[1], uint32_t _rout1[1], uint32_t _rout2[1]) { + int _numIn[1]; + remote_arg _pra[3]; + uint32_t _primIn[1]; + uint32_t _primROut[2]; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _COPY(_rout2, 0, _primROut, 4, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf_get_keys)(char* keys, int keysLen, int* maxLen, int* numKeys) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method_2(_adsp_perf_handle(), _mid, (char**)&keys, (uint32_t*)&keysLen, (uint32_t*)maxLen, (uint32_t*)numKeys); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_PERF_STUB_H diff --git a/src/adspmsgd_adsp1_stub.c b/src/adspmsgd_adsp1_stub.c new file mode 100644 index 0000000..d4c0050 --- /dev/null +++ b/src/adspmsgd_adsp1_stub.c @@ -0,0 +1,489 @@ +#ifndef _ADSPMSGD_ADSP1_STUB_H +#define _ADSPMSGD_ADSP1_STUB_H +/* + * 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 "adspmsgd_adsp1.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#include <string.h> +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSPMSGD_ADSP1_SLIM_H +#define _ADSPMSGD_ADSP1_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[3] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[3] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[3] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[0])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[2])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[4] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2])}; +static const char strings[30] = "deinit\0init2\0close\0open\0uri\0h\0"; +static const uint16_t methodStrings[7] = {19,24,28,13,28,0,7}; +static const uint16_t methodStringsArrays[4] = {0,3,6,5}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adspmsgd_adsp1_slim) = {4,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSPMSGD_ADSP1_SLIM_H +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_skel_handle_invoke)(remote_handle64 _h, uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_invoke)(_h, _sc, _pra); +} +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_init2)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_deinit)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method(_handle, _mid); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP1_STUB_H diff --git a/src/adspmsgd_adsp_stub.c b/src/adspmsgd_adsp_stub.c new file mode 100644 index 0000000..ab86f48 --- /dev/null +++ b/src/adspmsgd_adsp_stub.c @@ -0,0 +1,595 @@ +/* + * 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. + */ + +#ifndef _ADSPMSGD_ADSP_STUB_H +#define _ADSPMSGD_ADSP_STUB_H +#include "adspmsgd_adsp.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSPMSGD_ADSP_SLIM_H +#define _ADSPMSGD_ADSP_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[3] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[5] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[1])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[2] = {{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x10,0x4,5,5,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[3] = {&(methods[0]),&(methods[1]),&(methods[1])}; +static const char strings[56] = "buff_addr\0ion_flags\0buf_size\0deinit\0filter\0heapid\0init2\0"; +static const uint16_t methodStrings[8] = {31,43,10,36,20,0,29,50}; +static const uint16_t methodStringsArrays[3] = {0,7,6}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adspmsgd_adsp_slim) = {3,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSPMSGD_ADSP_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adspmsgd_adsp_handle +#define _const_adspmsgd_adsp_handle ((remote_handle)-1) +#endif //_const_adspmsgd_adsp_handle + +static void _adspmsgd_adsp_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adspmsgd_adsp_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adspmsgd_adsp_handle; + } +} + +static int _adspmsgd_adsp_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adspmsgd_adsp_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adspmsgd_adsp_handle(void) { + remote_handle* ph; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adspmsgd_adsp_handle, 0, sizeof(*ph), _adspmsgd_adsp_pls_ctor, "adspmsgd_adsp", _adspmsgd_adsp_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adspmsgd_adsp_handle, 0, sizeof(*ph), _adspmsgd_adsp_pls_ctor, "adspmsgd_adsp", _adspmsgd_adsp_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adspmsgd_adsp_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#include "Windows.h" +uint32_t _adspmsgd_adsp_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adspmsgd_adsp_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adspmsgd_adsp_handle(void) { + static remote_handle handle = _const_adspmsgd_adsp_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adspmsgd_adsp_pls_ctor("adspmsgd_adsp", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adspmsgd_adsp_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adspmsgd_adsp_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle_invoke)(_adspmsgd_adsp_handle(), _sc, _pra); +} + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], uint32_t _in2[1], uint32_t _in3[1], uint32_t _rout4[1]) { + int _numIn[1]; + remote_arg _pra[2]; + uint32_t _primIn[4]; + uint32_t _primROut[1]; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2, 0, 4); + _COPY(_primIn, 12, _in3, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _COPY(_rout4, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp_init)(int heapid, uint32 ion_flags, uint32 filter, uint32 buf_size, int* buff_addr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + return _stub_method(_adspmsgd_adsp_handle(), _mid, (uint32_t*)&heapid, (uint32_t*)&ion_flags, (uint32_t*)&filter, (uint32_t*)&buf_size, (uint32_t*)buff_addr); +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp_init2)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + return _stub_method_1(_adspmsgd_adsp_handle(), _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp_deinit)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method_1(_adspmsgd_adsp_handle(), _mid); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP_STUB_H diff --git a/src/adspmsgd_android.c b/src/adspmsgd_android.c new file mode 100644 index 0000000..edd45e5 --- /dev/null +++ b/src/adspmsgd_android.c @@ -0,0 +1,83 @@ +/* + * 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 "adspmsgd_apps.h" +#include "remote.h" + +#include <stdio.h> +#include <android/log.h> + +#define LOG_NODE_SIZE 258 +#define LOG_FILENAME_SIZE 30 +#define LOG_MSG_SIZE LOG_NODE_SIZE - LOG_FILENAME_SIZE - \ + sizeof(enum adspmsgd_apps_Level) - (3*sizeof(unsigned short)) + +typedef struct __attribute__((packed)) +{ + enum adspmsgd_apps_Level level; + unsigned short line; + unsigned short thread_id; + unsigned short asid; + char str[LOG_MSG_SIZE]; + char file [LOG_FILENAME_SIZE]; +} LogNode; + +static inline android_LogPriority convert_level_to_android_priority( + enum adspmsgd_apps_Level level) +{ + switch (level) { + case LOW: + return ANDROID_LOG_DEBUG; + case MEDIUM: + return ANDROID_LOG_INFO; + case HIGH: + return ANDROID_LOG_WARN; + case ERROR: + return ANDROID_LOG_ERROR; + case FATAL: + return ANDROID_LOG_FATAL; + default: + return ANDROID_LOG_DEFAULT; + } +} + +int adspmsgd_apps_log(const unsigned char *log_message_buffer, + int log_message_bufferLen) +{ + LogNode *logMessage = (LogNode *)log_message_buffer; + while ( (log_message_bufferLen > 0) && (logMessage != NULL)) { + __android_log_print(convert_level_to_android_priority(logMessage->level), + "adsprpc", "%s:%d:0x%x:%d:%s", logMessage->file, logMessage->line, + logMessage->thread_id, logMessage->asid, logMessage->str); + logMessage++; + log_message_bufferLen -= sizeof(LogNode); + }; + + return 0; +} diff --git a/src/adspmsgd_apps.c b/src/adspmsgd_apps.c new file mode 100644 index 0000000..f1871d3 --- /dev/null +++ b/src/adspmsgd_apps.c @@ -0,0 +1,82 @@ +/* + * 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 "adspmsgd_apps.h" +#include "remote.h" + +#include <stdio.h> + +#define LOG_NODE_SIZE 256 +#define LOG_FILENAME_SIZE 30 +#define LOG_MSG_SIZE LOG_NODE_SIZE - LOG_FILENAME_SIZE - \ + sizeof(enum adspmsgd_apps_Level) - (2*sizeof(unsigned short)) + +typedef struct __attribute__((packed)) +{ + enum adspmsgd_apps_Level level; + unsigned short line; + unsigned short thread_id; + char str[LOG_MSG_SIZE]; + char file [LOG_FILENAME_SIZE]; +} LogNode; + +#if 0 +static inline android_LogPriority convert_level_to_android_priority( + enum adspmsgd_apps_Level level) +{ + switch (level) { + case LOW: + return LOW; + case MEDIUM: + return MEDIUM; + case HIGH: + return HIGH; + case ERROR: + return ERROR; + case FATAL: + return FATAL; + default: + return 0; + } +} +#endif + +int adspmsgd_apps_log(const unsigned char *log_message_buffer, + int log_message_bufferLen) +{ + LogNode *logMessage = (LogNode *)log_message_buffer; + while ( (log_message_bufferLen > 0) && (logMessage != NULL)) { + printf("adsprpc: %s:%d:0x%x:%s", logMessage->file, logMessage->line, + logMessage->thread_id, logMessage->str); + logMessage++; + log_message_bufferLen -= sizeof(LogNode); + }; + + return 0; +} diff --git a/src/adspmsgd_apps_skel.c b/src/adspmsgd_apps_skel.c new file mode 100644 index 0000000..acc3361 --- /dev/null +++ b/src/adspmsgd_apps_skel.c @@ -0,0 +1,494 @@ +/* + * 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. + */ + +#ifndef _ADSPMSGD_APPS_SKEL_H +#define _ADSPMSGD_APPS_SKEL_H +#include "adspmsgd_apps.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSPMSGD_APPS_SLIM_H +#define _ADSPMSGD_APPS_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const Type types[1] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1}}; +static const Parameter parameters[1] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[1] = {(&(parameters[0]))}; +static const Method methods[1] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x4,0x0,2,1,(&(parameterArrays[0])),0x4,0x0}}; +static const Method* const methodArrays[1] = {&(methods[0])}; +static const char strings[23] = "log_message_buffer\0log\0"; +static const uint16_t methodStrings[2] = {19,0}; +static const uint16_t methodStringsArrays[1] = {0}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adspmsgd_apps_slim) = {1,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSPMSGD_APPS_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _skel_method(int (*_pfn)(char*, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + uint32_t* _primIn; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 2) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, *_in0Len)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(adspmsgd_apps_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method((void*)__QAIC_IMPL(adspmsgd_apps_log), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_APPS_SKEL_H diff --git a/src/adsprpcd.c b/src/adsprpcd.c new file mode 100644 index 0000000..9cf3f68 --- /dev/null +++ b/src/adsprpcd.c @@ -0,0 +1,71 @@ +/* + * 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. + */ +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_PRINT_ERROR +#endif + +#include <stdio.h> +#include <dlfcn.h> +#include <unistd.h> +#include "verify.h" + + +#ifndef ADSP_DEFAULT_LISTENER_NAME +#define ADSP_DEFAULT_LISTENER_NAME "libadsp_default_listener.so" +#endif + +typedef int (*adsp_default_listener_start_t)(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + + int nErr = 0; + void *adsphandler = NULL; + adsp_default_listener_start_t listener_start; + + VERIFY_EPRINTF("adsp daemon starting"); + while (1) { + if(NULL != (adsphandler = dlopen(ADSP_DEFAULT_LISTENER_NAME, RTLD_NOW))) { + if(NULL != (listener_start = + (adsp_default_listener_start_t)dlsym(adsphandler, "adsp_default_listener_start"))) { + VERIFY_IPRINTF("adsp_default_listener_start called"); + listener_start(argc, argv); + } + if(0 != dlclose(adsphandler)) { + VERIFY_EPRINTF("dlclose failed"); + } + } else { + VERIFY_EPRINTF("adsp daemon error %s", dlerror()); + } + VERIFY_EPRINTF("adsp daemon will restart after 25ms..."); + usleep(25000); + } + VERIFY_EPRINTF("adsp daemon exiting %x", nErr); +bail: + return nErr; +} diff --git a/src/apps_mem_imp.c b/src/apps_mem_imp.c new file mode 100644 index 0000000..d6f2ccb --- /dev/null +++ b/src/apps_mem_imp.c @@ -0,0 +1,244 @@ +/* + * 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. + */ +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_PRINT_ERROR +#endif /* VERIFY_PRINT_ERROR */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <sys/mman.h> +#include "apps_mem.h" +#include "remote64.h" +#include "rpcmem.h" +#include "verify.h" +#include "rpcmem.h" +#include "AEEQList.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "fastrpc_apps_user.h" +#include "platform_libs.h" + +#define ADSP_MMAP_HEAP_ADDR 4 +#define ADSP_MMAP_REMOTE_HEAP_ADDR 8 +#define ADSP_MMAP_ADD_PAGES 0x1000 + +static QList memlst; +static pthread_mutex_t memmt; + +struct mem_info { + QNode qn; + uint64 vapps; + uint64 vadsp; + int32 size; + int32 mapped; +}; + +/* +These should be called in some static constructor of the .so that +uses rpcmem. + +I moved them into fastrpc_apps_user.c because there is no gurantee in +the order of when constructors are called. +*/ + +static int apps_mem_init(void) { + QList_Ctor(&memlst); + pthread_mutex_init(&memmt, 0); + return AEE_SUCCESS; +} + +void apps_mem_deinit(void) { + QNode *pn; + while ((pn = QList_PopZ(&memlst)) != NULL) { + struct mem_info *mfree = STD_RECOVER_REC(struct mem_info, qn, pn); + + if (mfree->vapps) { + if(mfree->mapped) { + munmap((void*)(uintptr_t)mfree->vapps, mfree->size); + } else { + rpcmem_free_internal((void *)(uintptr_t)mfree->vapps); + } + } + free(mfree); + mfree = NULL; + } + pthread_mutex_destroy(&memmt); +} +PL_DEFINE(apps_mem, apps_mem_init, apps_mem_deinit); + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32 lflags, uint32 rflags, uint64 vin, int64 len, uint64* vapps, uint64* vadsp) __QAIC_IMPL_ATTRIBUTE { + struct mem_info *minfo = 0; + int nErr = 0; + void* buf = 0; + uint64_t pbuf; + int fd = -1; + + (void)vin; + VERIFYC(NULL != (minfo = malloc(sizeof(*minfo))), AEE_ENOMEMORY); + QNode_CtorZ(&minfo->qn); + *vadsp = 0; + if (rflags == ADSP_MMAP_HEAP_ADDR || rflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + VERIFY(AEE_SUCCESS == (nErr = remote_mmap64(-1, rflags, 0, len, (uint64_t*)vadsp))); + *vapps = 0; + minfo->vapps = 0; + } else { + if ((rflags != ADSP_MMAP_ADD_PAGES) || + ((rflags == ADSP_MMAP_ADD_PAGES) && !is_kernel_alloc_supported(-1, -1))) { + VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), AEE_ENORPCMEMORY); + fd = rpcmem_to_fd_internal(buf); + VERIFYC(fd > 0, AEE_EINVALIDFD); + } + VERIFY(AEE_SUCCESS == (nErr = remote_mmap64(fd, rflags, (uint64_t)buf, len, (uint64_t*)vadsp))); + pbuf = (uint64_t)buf; + *vapps = pbuf; + minfo->vapps = *vapps; + } + minfo->vadsp = *vadsp; + minfo->size = len; + minfo->mapped = 0; + pthread_mutex_lock(&memmt); + QList_AppendNode(&memlst, &minfo->qn); + pthread_mutex_unlock(&memmt); +bail: + if(nErr) { + if(buf) { + rpcmem_free_internal(buf); + buf = NULL; + } + if(minfo) { + free(minfo); + minfo = NULL; + } + VERIFY_EPRINTF("Error %x: apps_mem_request_mmap64 failed\n", nErr); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_request_map)(int heapid, uint32 lflags, uint32 rflags, uint32 vin, int32 len, uint32* vapps, uint32* vadsp) __QAIC_IMPL_ATTRIBUTE { + uint64 vin1, vapps1, vadsp1; + int64 len1; + int nErr = AEE_SUCCESS; + vin1 = (uint64)vin; + len1 = (int64)len; + nErr = apps_mem_request_map64(heapid, lflags, rflags, vin1, len1, &vapps1, &vadsp1); + *vapps = (uint32)vapps1; + *vadsp = (uint32)vadsp1; + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: apps_mem_request_map failed\n", nErr); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_request_unmap64)(uint64 vadsp, int64 len) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct mem_info *minfo, *mfree = 0; + QNode *pn, *pnn; + VERIFY(0 == (nErr = remote_munmap64((uint64_t)vadsp, len))); + pthread_mutex_lock(&memmt); + QLIST_NEXTSAFE_FOR_ALL(&memlst, pn, pnn) { + minfo = STD_RECOVER_REC(struct mem_info, qn, pn); + if(minfo->vadsp == vadsp) { + mfree = minfo; + QNode_Dequeue(&minfo->qn); + break; + } + } + pthread_mutex_unlock(&memmt); + VERIFYC(mfree, AEE_ENOSUCHMAP); + if(mfree->mapped) { + munmap((void*)(uintptr_t)mfree->vapps, mfree->size); + } else { + if (mfree->vapps) + rpcmem_free_internal((void *)(uintptr_t)mfree->vapps); + } + free(mfree); + mfree = NULL; +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: apps_mem_request_unmap64 failed\n", nErr); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_request_unmap)(uint32 vadsp, int32 len) __QAIC_IMPL_ATTRIBUTE { + uint64 vadsp1 = (uint64)vadsp; + int64 len1 = (int64)len; + int nErr = apps_mem_request_unmap64(vadsp1, len1); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: apps_mem_request_unmap failed\n", nErr); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_share_map)(int fd, int size, uint64* vapps, uint64* vadsp) __QAIC_IMPL_ATTRIBUTE { + struct mem_info *minfo = 0; + int nErr = AEE_SUCCESS; + void* buf = 0; + uint64_t pbuf; + VERIFYC(0 != (minfo = malloc(sizeof(*minfo))), AEE_ENOMEMORY); + QNode_CtorZ(&minfo->qn); + VERIFYC(fd > 0, AEE_EINVALIDFD); + *vadsp = 0; + VERIFYC(MAP_FAILED != (buf = (void *)mmap(NULL, size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)), AEE_EMMAP); + VERIFY(AEE_SUCCESS == (nErr = remote_mmap64(fd, 0, (uint64_t)buf, size, (uint64_t*)vadsp))); + pbuf = (uint64_t)buf; + *vapps = pbuf; + minfo->vapps = *vapps; + minfo->vadsp = *vadsp; + minfo->size = size; + minfo->mapped = 1; + pthread_mutex_lock(&memmt); + QList_AppendNode(&memlst, &minfo->qn); + pthread_mutex_unlock(&memmt); +bail: + if(nErr) { + if(buf) { + munmap(buf, size); + } + if(minfo) { + free(minfo); + minfo = NULL; + } + VERIFY_EPRINTF("Error %x: apps_mem_share_map failed\n", nErr); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_share_unmap)(uint64 vadsp, int size) __QAIC_IMPL_ATTRIBUTE { + int64 len1 = (int64)size; + int nErr = AEE_SUCCESS; + nErr = apps_mem_request_unmap64(vadsp, len1); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: apps_mem_share_unmap failed\n", nErr); + } + return nErr; +} diff --git a/src/apps_mem_skel.c b/src/apps_mem_skel.c new file mode 100644 index 0000000..8bd74d5 --- /dev/null +++ b/src/apps_mem_skel.c @@ -0,0 +1,617 @@ +/* + * 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. + */ +#ifndef _APPS_MEM_SKEL_H +#define _APPS_MEM_SKEL_H +#include "apps_mem.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _APPS_MEM_SLIM_H +#define _APPS_MEM_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[6] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,3,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x8,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x8,3,0}}; +static const Parameter* const parameterArrays[20] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[1])),(&(parameters[3])),(&(parameters[4])),(&(parameters[5])),(&(parameters[5])),(&(parameters[0])),(&(parameters[1])),(&(parameters[1])),(&(parameters[1])),(&(parameters[0])),(&(parameters[2])),(&(parameters[2])),(&(parameters[0])),(&(parameters[0])),(&(parameters[5])),(&(parameters[5])),(&(parameters[3])),(&(parameters[0]))}; +static const Method methods[6] = {{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x14,0x8,7,7,(&(parameterArrays[7])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[10])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x20,0x10,11,7,(&(parameterArrays[0])),0x8,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x10,0x0,6,2,(&(parameterArrays[3])),0x8,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x8,0x10,4,4,(&(parameterArrays[14])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0xc,0x0,4,2,(&(parameterArrays[18])),0x8,0x0}}; +static const Method* const methodArrays[6] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[5])}; +static const char strings[130] = "request_unmap64\0request_map64\0request_unmap\0share_unmap\0request_map\0share_map\0ion_flags\0rflags\0heapid\0vadsp\0vapps\0size\0len\0vin\0fd\0"; +static const uint16_t methodStrings[30] = {16,95,78,88,123,119,108,102,56,95,78,88,123,119,108,102,68,127,114,108,102,44,102,114,0,102,119,30,102,119}; +static const uint16_t methodStringsArrays[6] = {8,27,0,24,16,21}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(apps_mem_slim) = {6,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_APPS_MEM_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _skel_method(int (*_pfn)(uint64_t, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint64_t _in0[1]; + uint32_t _in1[1]; + uint64_t* _primIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 1) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _COPY(_in1, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn(*_in0, *_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_1(int (*_pfn)(uint32_t, uint32_t, uint64_t*, uint64_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t _in1[1]; + uint64_t _rout2[1]; + uint64_t _rout3[1]; + uint32_t* _primIn; + int _numIn[1]; + uint64_t* _primROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 2) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 16); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn(*_in0, *_in1, _rout2, _rout3)); + _COPY(_primROut, 0, _rout2, 0, 8); + _COPY(_primROut, 8, _rout3, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_2(int (*_pfn)(uint64_t, uint64_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint64_t _in0[1]; + uint64_t _in1[1]; + uint64_t* _primIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 1) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 16); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _COPY(_in1, 0, _primIn, 8, 8); + _TRY(_nErr, _pfn(*_in0, *_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_3(int (*_pfn)(uint32_t, uint32_t, uint32_t, uint64_t, uint64_t, uint64_t*, uint64_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t _in1[1]; + uint32_t _in2[1]; + uint64_t _in3[1]; + uint64_t _in4[1]; + uint64_t _rout5[1]; + uint64_t _rout6[1]; + uint64_t* _primIn; + int _numIn[1]; + uint64_t* _primROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 2) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 32); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 16); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _COPY(_in3, 0, _primIn, 16, 8); + _COPY(_in4, 0, _primIn, 24, 8); + _TRY(_nErr, _pfn(*_in0, *_in1, *_in2, *_in3, *_in4, _rout5, _rout6)); + _COPY(_primROut, 0, _rout5, 0, 8); + _COPY(_primROut, 8, _rout6, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_4(int (*_pfn)(uint32_t, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t _in1[1]; + uint32_t* _primIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 1) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn(*_in0, *_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_5(int (*_pfn)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t*, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t _in1[1]; + uint32_t _in2[1]; + uint32_t _in3[1]; + uint32_t _in4[1]; + uint32_t _rout5[1]; + uint32_t _rout6[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 2) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 20); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _COPY(_in3, 0, _primIn, 12, 4); + _COPY(_in4, 0, _primIn, 16, 4); + _TRY(_nErr, _pfn(*_in0, *_in1, *_in2, *_in3, *_in4, _rout5, _rout6)); + _COPY(_primROut, 0, _rout5, 0, 4); + _COPY(_primROut, 4, _rout6, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(apps_mem_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method_5((void*)__QAIC_IMPL(apps_mem_request_map), _sc, _pra); + case 1: + return _skel_method_4((void*)__QAIC_IMPL(apps_mem_request_unmap), _sc, _pra); + case 2: + return _skel_method_3((void*)__QAIC_IMPL(apps_mem_request_map64), _sc, _pra); + case 3: + return _skel_method_2((void*)__QAIC_IMPL(apps_mem_request_unmap64), _sc, _pra); + case 4: + return _skel_method_1((void*)__QAIC_IMPL(apps_mem_share_map), _sc, _pra); + case 5: + return _skel_method((void*)__QAIC_IMPL(apps_mem_share_unmap), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_APPS_MEM_SKEL_H diff --git a/src/apps_remotectl_skel.c b/src/apps_remotectl_skel.c new file mode 100644 index 0000000..afd3c38 --- /dev/null +++ b/src/apps_remotectl_skel.c @@ -0,0 +1,499 @@ +/* + * 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. + */ +#ifndef _APPS_REMOTECTL_SKEL_H +#define _APPS_REMOTECTL_SKEL_H +#include "apps_remotectl.h" +#include "remote.h" +#include <string.h> +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} allocator; + +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + + +static __inline int allocator_alloc(allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + + +static __inline void allocator_deinit(allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +static __inline void allocator_init(allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _APPS_REMOTECTL_SLIM_H +#define _APPS_REMOTECTL_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const Type types[1] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1}}; +static const Parameter parameters[4] = {{0x8,{{(const uintptr_t)0x0,0}}, 4,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x8,{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0}}; +static const Parameter* const parameterArrays[7] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[1])),(&(parameters[3])),(&(parameters[2])),(&(parameters[1]))}; +static const Method methods[2] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x8,0x8,6,4,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[4])),0x4,0x4}}; +static const Method* const methodArrays[2] = {&(methods[0]),&(methods[1])}; +static const char strings[36] = "dlerror\0handle\0close\0nErr\0name\0open\0"; +static const uint16_t methodStrings[9] = {31,26,8,0,21,15,8,0,21}; +static const uint16_t methodStringsArrays[2] = {0,5}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(apps_remotectl_slim) = {2,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_APPS_REMOTECTL_SLIM_H +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE_LINE__ ": error: %d\n", (int)(ee)));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _skel_method(int (*_pfn)(uint32_t, char*, uint32_t, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _rout1[1]; + uint32_t _rout1Len[1]; + uint32_t _rout2[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 3) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, (int)((_praROut[0].buf.nLen / 1)) >= (int)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, *_rout1, *_rout1Len, _rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_1(int (*_pfn)(char*, uint32_t*, char*, uint32_t, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + uint32_t _rout1[1]; + char* _rout2[1]; + uint32_t _rout2Len[1]; + uint32_t _rout3[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc)); + _ASSERT(_nErr, (_pra + 4) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + if(_in0Len[0] > 0) + { + _in0[0][(_in0Len[0] - 1)] = 0; + } + _COPY(_rout2Len, 0, _primIn, 4, 4); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, (int)((_praROut[0].buf.nLen / 1)) >= (int)(_rout2Len[0])); + _rout2[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, _rout1, *_rout2, *_rout2Len, _rout3)); + _COPY(_primROut, 0, _rout1, 0, 4); + _COPY(_primROut, 4, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(apps_remotectl_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method_1((void*)__QAIC_IMPL(apps_remotectl_open), _sc, _pra); + case 1: + return _skel_method((void*)__QAIC_IMPL(apps_remotectl_close), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_APPS_REMOTECTL_SKEL_H diff --git a/src/apps_std_imp.c b/src/apps_std_imp.c new file mode 100644 index 0000000..d2559c6 --- /dev/null +++ b/src/apps_std_imp.c @@ -0,0 +1,1076 @@ +/* + * 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. + */ + +#ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif// _CRT_SECURE_NO_WARNINGS + +#pragma warning( disable : 4996 ) +#define strtok_r strtok_s +#define S_ISDIR(mode) (mode & S_IFDIR) +#endif //_WIN32 + +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_PRINT_ERROR +#endif //VERIFY_PRINT_ERROR +#define FARF_ERROR 1 + +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> +#include <dlfcn.h> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include "remote.h" +#include "verify.h" +#include "apps_std.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "AEEatomic.h" +#include "AEEQList.h" +#include "platform_libs.h" +#include "fastrpc_apps_user.h" +#include "HAP_farf.h" +#include "rpcmem.h" + +#ifndef _WIN32 +#include <unistd.h> +#endif // _WiN32 + +#ifndef C_ASSERT +#define C_ASSERT(test) \ + switch(0) {\ + case 0:\ + case test:;\ + } +#endif //C_ASSERT + +#define APPS_FD_BASE 100 +#define ERRNO (errno == 0 ? -1 : errno) +#define APPS_STD_STREAM_FILE 1 +#define APPS_STD_STREAM_BUF 2 + +#define ION_HEAP_ID_QSEECOM 27 + +#define FREEIF(pv) \ + do {\ + if(pv) { \ + void* tmp = (void*)pv;\ + pv = 0;\ + free(tmp);\ + tmp = 0;\ + } \ + } while(0) + +extern int get_domain_id(); + +struct apps_std_buf_info { + char* fbuf; + int flen; + int pos; +}; + +struct apps_std_info { + QNode qn; + int type; + union { + FILE* stream; + struct apps_std_buf_info binfo; + } u; + apps_std_FILE fd; +}; + +static QList apps_std_qlst; +static pthread_mutex_t apps_std_mt; + +int setenv(const char *name, const char *value, int overwrite); +int unsetenv(const char *name); + +int apps_std_init(void) { + QList_Ctor(&apps_std_qlst); + pthread_mutex_init(&apps_std_mt, 0); + return AEE_SUCCESS; +} + +void apps_std_deinit(void) { + pthread_mutex_destroy(&apps_std_mt); +} + +PL_DEFINE(apps_std, apps_std_init, apps_std_deinit); + +static int apps_std_FILE_free(struct apps_std_info* sfree) { + int nErr = AEE_SUCCESS; + + pthread_mutex_lock(&apps_std_mt); + QNode_Dequeue(&sfree->qn); + pthread_mutex_unlock(&apps_std_mt); + + free(sfree); + sfree = NULL; + return nErr; +} + +static int apps_std_FILE_alloc(FILE *stream, apps_std_FILE *fd) { + struct apps_std_info *sinfo = 0, *info; + QNode *pn = 0; + apps_std_FILE prevfd = APPS_FD_BASE - 1; + int nErr = AEE_SUCCESS; + + VERIFYC(0 != (sinfo = calloc(1, sizeof(*sinfo))), AEE_ENOMEMORY); + QNode_CtorZ(&sinfo->qn); + sinfo->type = APPS_STD_STREAM_FILE; + pthread_mutex_lock(&apps_std_mt); + pn = QList_GetFirst(&apps_std_qlst); + if(pn) { + info = STD_RECOVER_REC(struct apps_std_info, qn, pn); + prevfd = info->fd; + QLIST_FOR_REST(&apps_std_qlst, pn) { + info = STD_RECOVER_REC(struct apps_std_info, qn, pn); + if (info->fd != prevfd + 1) { + sinfo->fd = prevfd + 1; + QNode_InsPrev(pn, &sinfo->qn); + break; + } + prevfd = info->fd; + } + } + if(!QNode_IsQueuedZ(&sinfo->qn)) { + sinfo->fd = prevfd + 1; + QList_AppendNode(&apps_std_qlst, &sinfo->qn); + } + pthread_mutex_unlock(&apps_std_mt); + + sinfo->u.stream = stream; + *fd = sinfo->fd; + +bail: + if(nErr) { + FREEIF(sinfo); + VERIFY_EPRINTF("Error %x: apps_std_FILE_alloc failed\n", nErr); + } + return nErr; +} + +static int apps_std_FILE_get(apps_std_FILE fd, struct apps_std_info** info) { + struct apps_std_info *sinfo = 0; + QNode *pn, *pnn; + FILE* stream = NULL; + int nErr = AEE_ENOSUCHSTREAM; + + pthread_mutex_lock(&apps_std_mt); + QLIST_NEXTSAFE_FOR_ALL(&apps_std_qlst, pn, pnn) { + sinfo = STD_RECOVER_REC(struct apps_std_info, qn, pn); + if(sinfo->fd == fd) { + *info = sinfo; + nErr = AEE_SUCCESS; + break; + } + } + pthread_mutex_unlock(&apps_std_mt); + + return nErr; +} + +static void apps_std_FILE_set_buffer_stream(struct apps_std_info* sinfo, char* fbuf, int flen, int pos) { + pthread_mutex_lock(&apps_std_mt); + fclose(sinfo->u.stream); + sinfo->type = APPS_STD_STREAM_BUF; + sinfo->u.binfo.fbuf = fbuf; + sinfo->u.binfo.flen = flen; + sinfo->u.binfo.pos = pos; + pthread_mutex_unlock(&apps_std_mt); +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fopen)(const char* name, const char* mode, apps_std_FILE* psout) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + FILE* stream = fopen(name, mode); + if(stream) { + return apps_std_FILE_alloc(stream, psout); + } else { + nErr = AEE_ENOSUCHFILE; + } + if(nErr != AEE_SUCCESS) { + // Ignoring this error, as fopen happens on all ADSP_LIBRARY_PATHs + VERIFY_IPRINTF("Error %x: fopen for %s failed. errno: %s\n", nErr, name, strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_freopen)(apps_std_FILE sin, const char* name, const char* mode, apps_std_FILE* psout) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + FILE* stream; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + VERIFY(sinfo->type == APPS_STD_STREAM_FILE); + stream = freopen(name, mode, sinfo->u.stream); + if(stream) { + FARF(HIGH, "freopen success: %s %x\n", name, stream); + return apps_std_FILE_alloc(stream, psout); + } else { + nErr = AEE_EFOPEN; + } +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: freopen for %s failed. errno: %s\n", nErr, name, strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fflush)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + VERIFYC(0 == fflush(sinfo->u.stream), AEE_EFFLUSH); + } +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: fflush for %x failed. errno: %s\n", nErr, sin, strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fclose)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + VERIFYC(0 == fclose(sinfo->u.stream), AEE_EFCLOSE); + } else { + if(sinfo->u.binfo.fbuf) { + rpcmem_free_internal(sinfo->u.binfo.fbuf); + sinfo->u.binfo.fbuf = NULL; + } + } + apps_std_FILE_free(sinfo); +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: freopen for %x failed. errno: %s\n", nErr, sin, strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fread)(apps_std_FILE sin, byte* buf, int bufLen, int* bytesRead, int* bEOF) __QAIC_IMPL_ATTRIBUTE { + int out = 0, nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + out = fread(buf, 1, bufLen, sinfo->u.stream); + *bEOF = FALSE; + if(out <= bufLen) { + int err; + if(0 == out && (0 != (err = ferror(sinfo->u.stream)))) { + nErr = AEE_EFREAD; + VERIFY_EPRINTF("Error %x: fread returning %d bytes, requested was %d bytes, errno is %x\n", nErr, out, bufLen, err); + return nErr; + } + *bEOF = feof(sinfo->u.stream); + } + *bytesRead = out; + } else { + *bytesRead = std_memscpy(buf, bufLen, sinfo->u.binfo.fbuf + sinfo->u.binfo.pos, + sinfo->u.binfo.flen - sinfo->u.binfo.pos); + sinfo->u.binfo.pos += *bytesRead; + *bEOF = sinfo->u.binfo.pos == sinfo->u.binfo.flen ? TRUE : FALSE; + } + FARF(HIGH, "fread returning %d %d 0", out, bufLen); +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fwrite)(apps_std_FILE sin, const byte* buf, int bufLen, int* bytesRead, int* bEOF) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + int out = fwrite(buf, 1, bufLen, sinfo->u.stream); + *bEOF = FALSE; + if(out <= bufLen) { + int err; + if(0 == out && (0 != (err = ferror(sinfo->u.stream)))) { + nErr = AEE_EFWRITE; + VERIFY_EPRINTF("Error %x: fwrite returning %d bytes, requested was %d bytes, errno is %x\n", nErr, out, bufLen, err); + return nErr; + } + *bEOF = feof(sinfo->u.stream); + } + *bytesRead = out; + } else { + nErr = AEE_EFWRITE; + } +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fgetpos)(apps_std_FILE sin, byte* pos, int posLen, int* posLenReq) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + fpos_t fpos; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + if(0 == fgetpos(sinfo->u.stream, &fpos)) { + std_memmove(pos, &fpos, STD_MIN((int)sizeof(fpos), posLen)); + *posLenReq = sizeof(fpos); + return AEE_SUCCESS; + } else { + nErr = AEE_EFGETPOS; + } + } else { + nErr = AEE_EFGETPOS; + } +bail: + VERIFY_EPRINTF("Error %x: fgetpos failed for %x, errno is %s\n", nErr, sin, strerror(ERRNO)); + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fsetpos)(apps_std_FILE sin, const byte* pos, int posLen) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + fpos_t fpos; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + if(sizeof(fpos) != posLen) { + return AEE_EBADSIZE; + } + std_memmove(&fpos, pos, sizeof(fpos)); + if(0 == fsetpos(sinfo->u.stream, &fpos)) { + return AEE_SUCCESS; + } else { + nErr = AEE_EFSETPOS; + } + } else { + nErr = AEE_EFSETPOS; + } +bail: + VERIFY_EPRINTF("Error %x: fsetpos failed for %x, errno is %s\n", nErr, sin, strerror(ERRNO)); + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_ftell)(apps_std_FILE sin, int* pos) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + if((*pos = ftell(sinfo->u.stream)) >= 0) { + return AEE_SUCCESS; + } else { + nErr = AEE_EFTELL; + } + } else { + *pos = sinfo->u.binfo.pos; + return AEE_SUCCESS; + } +bail: + VERIFY_EPRINTF("Error %x: ftell failed for %x, errno is %s\n", nErr, sin, strerror(ERRNO)); + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fseek)(apps_std_FILE sin, int offset, apps_std_SEEK whence) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + int op = (int)whence; + struct apps_std_info* sinfo = 0; + + C_ASSERT(APPS_STD_SEEK_SET == SEEK_SET); + C_ASSERT(APPS_STD_SEEK_CUR == SEEK_CUR); + C_ASSERT(APPS_STD_SEEK_END == SEEK_END); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + if(0 == fseek(sinfo->u.stream, offset, whence)) { + return AEE_SUCCESS; + } else { + nErr = AEE_EFSEEK; + } + } else { + switch(op) { + case APPS_STD_SEEK_SET: + VERIFYC(offset <= sinfo->u.binfo.flen, AEE_EFSEEK); + sinfo->u.binfo.pos = offset; + break; + case APPS_STD_SEEK_CUR: + VERIFYC(offset + sinfo->u.binfo.pos <= sinfo->u.binfo.flen, AEE_EFSEEK); + sinfo->u.binfo.pos += offset; + break; + case APPS_STD_SEEK_END: + VERIFYC(offset + sinfo->u.binfo.flen <= sinfo->u.binfo.flen, AEE_EFSEEK); + sinfo->u.binfo.pos += offset + sinfo->u.binfo.flen; + break; + } + } +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: fseek failed for %x, errno is %s\n", nErr, sin, strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_rewind)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + rewind(sinfo->u.stream); + } else { + sinfo->u.binfo.pos = 0; + } +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_feof)(apps_std_FILE sin, int* bEOF) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + *bEOF = feof(sinfo->u.stream); + } else { + nErr = AEE_EUNSUPPORTED; + } +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_ferror)(apps_std_FILE sin, int* err) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + *err = ferror(sinfo->u.stream); + } else { + nErr = AEE_EUNSUPPORTED; + } +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_clearerr)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + clearerr(sinfo->u.stream); + } else { + nErr = AEE_EUNSUPPORTED; + } +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_flen)(apps_std_FILE sin, uint64* len) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + struct stat st_buf; + int fd = fileno(sinfo->u.stream); + C_ASSERT(sizeof(st_buf.st_size) <= sizeof(*len)); + if(fd == -1) { + nErr = AEE_EFLEN; + VERIFY_EPRINTF("Error %x: flen failed for %x, errno is %s\n", nErr, sin, strerror(ERRNO)); + return nErr; + } + if(0 != fstat(fd, &st_buf)) { + nErr = AEE_EFLEN; + VERIFY_EPRINTF("Error %x: flen failed for %x, errno is %s\n", nErr, sin, strerror(ERRNO)); + return nErr; + } + *len = st_buf.st_size; + } else { + *len = sinfo->u.binfo.flen; + } +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_print_string)(const char* str) __QAIC_IMPL_ATTRIBUTE { + printf("%s", str); + return AEE_SUCCESS; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_getenv)(const char* name, char* val, int valLen, int* valLenReq) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + char* vv = getenv(name); + if(vv) { + *valLenReq = std_strlen(vv) + 1; + std_strlcpy(val, vv, valLen); + return AEE_SUCCESS; + } + nErr = AEE_EGETENV; + VERIFY_IPRINTF("Error %x: apps_std getenv failed: %s %s\n", nErr, name, strerror(ERRNO)); + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_setenv)(const char* name, const char* val, int override) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; +#ifdef _WIN32 + return AEE_EUNSUPPORTED; +#else //_WIN32 + if(0 != setenv(name, val, override)) { + nErr = AEE_ESETENV; + VERIFY_EPRINTF("Error %x: setenv failed for %s, errno is %s\n", nErr, name, strerror(ERRNO)); + return nErr; + } + return AEE_SUCCESS; +#endif //_WIN32 +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_unsetenv)(const char* name) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; +#ifdef _WIN32 + return AEE_EUNSUPPORTED; +#else //_WIN32 + if(0 != unsetenv(name)) { + nErr = AEE_ESETENV; + VERIFY_EPRINTF("Error %x: unsetenv failed for %s, errno is %s\n", nErr, name, strerror(ERRNO)); + return nErr; + } + return AEE_SUCCESS; +#endif //_WIN32 +} + + +#if (defined LE_ENABLE) +static char* ADSP_LIBRARY_PATH=";/usr/lib/rfsa/adsp;/usr/lib;/dsp;/usr/share/fastrpc"; +static char* ADSP_AVS_CFG_PATH=";/etc/acdbdata/"; +#elif (defined __BRILLO__) +static char* ADSP_LIBRARY_PATH=";/system/etc/lib/rfsa/adsp;/system/vendor/etc/lib/rfsa/adsp;/dsp"; +static char* ADSP_AVS_CFG_PATH=";/etc/acdbdata/"; +#elif (defined _ANDROID) || (defined ANDROID) +#if (defined ANDROID_P) && (defined FULL_TREBLE) +#ifdef SYSTEM_RPC_LIBRARY +static char* ADSP_LIBRARY_PATH=";/system/lib/rfsa/adsp"; +static char* ADSP_AVS_CFG_PATH=";/etc/acdbdata/"; +#else +static char* ADSP_LIBRARY_PATH=";/vendor/lib/rfsa/adsp;/vendor/dsp"; +static char* ADSP_AVS_CFG_PATH=";/vendor/etc/acdbdata/"; +#endif +#else +static char* ADSP_LIBRARY_PATH=";/system/lib/rfsa/adsp;/system/vendor/lib/rfsa/adsp;/dsp;/vendor/dsp"; +static char* ADSP_AVS_CFG_PATH=";/etc/acdbdata/;/vendor/etc/acdbdata/"; +#endif +#elif (defined __QNX__) +static char* ADSP_LIBRARY_PATH="/radio/lib/firmware"; +#else +static char* ADSP_LIBRARY_PATH=""; +#endif + +#define EMTPY_STR "" +#define ENV_LEN_GUESS 256 + +static int get_dirlist_from_env(const char* envvarname, char** ppDirList){ + char *envList = NULL; + char *envListBuf = NULL; + char *dirList = NULL; + char *dirListBuf = NULL; + char *srcStr = NULL; + int nErr = AEE_SUCCESS; + int envListLen = 0; + int listLen = 0; + int envLenGuess = STD_MAX(ENV_LEN_GUESS, 1 + std_strlen(ADSP_LIBRARY_PATH)); + + VERIFYC(NULL != ppDirList, AEE_EMEMPTR); + + VERIFYC(envListBuf = (char*)malloc(sizeof(char) * envLenGuess), AEE_ENOMEMORY); + envList = envListBuf; + *envList = '\0'; + if (0 == apps_std_getenv(envvarname, envList, envLenGuess, &envListLen)) { + if (envLenGuess < envListLen) { + FREEIF(envListBuf); + VERIFYC(envListBuf = realloc(envListBuf, sizeof(char) * envListLen), AEE_ENOMEMORY); + envList = envListBuf; + VERIFY(0 == (nErr = apps_std_getenv(envvarname, envList, envListLen, &listLen))); + } + } else if(std_strncmp(envvarname, "ADSP_LIBRARY_PATH", 17) == 0) { + envListLen = listLen = 1 + std_strlcpy(envListBuf, ADSP_LIBRARY_PATH, envLenGuess); + } else if(std_strncmp(envvarname, "ADSP_AVS_CFG_PATH", 17) == 0) { + envListLen = listLen = 1 + std_strlcpy(envListBuf, ADSP_AVS_CFG_PATH, envLenGuess); + } + + /* + * Allocate mem. to copy envvarname. + * If envvarname not set, allocate mem to create an empty string + */ + if('\0' != *envList) { + srcStr = envList; + } else { + srcStr = EMTPY_STR; + envListLen = std_strlen(EMTPY_STR) + 1; + } + VERIFYC(dirListBuf = (char*)malloc(sizeof(char) * envListLen), AEE_ENOMEMORY); + dirList = dirListBuf; + std_strlcpy(dirList, srcStr, envListLen); + *ppDirList = dirListBuf; +bail: + FREEIF(envListBuf); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: get dirlist from env failed for %s\n", nErr, envvarname); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fopen_with_env)(const char* envvarname, + const char* delim, const char* name, const char* mode, + apps_std_FILE* psout) __QAIC_IMPL_ATTRIBUTE { + + int nErr = AEE_SUCCESS; + char *dirName = NULL; + char *pos = NULL; + char *dirListBuf = NULL; + char *dirList = NULL; + char *absName = NULL; + uint16 absNameLen = 0; + int domain; + + VERIFYC(NULL != mode, AEE_EINVALIDMODE); + VERIFYC(NULL != delim, AEE_EINVALIDFORMAT); + VERIFYC(NULL != name, AEE_EMEMPTR); + + VERIFY(0 == (nErr = get_dirlist_from_env(envvarname, &dirListBuf ))); + VERIFYC(NULL != (dirList = dirListBuf), AEE_EMEMPTR); + + while(dirList) + { + pos = strstr(dirList, delim); + dirName = dirList; + if (pos) { + *pos = '\0'; + dirList = pos + std_strlen(delim); + } else { + dirList = 0; + } + + // Account for slash char + absNameLen = std_strlen(dirName) + std_strlen(name) + 2; + VERIFYC(NULL != (absName = (char*)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); + if ('\0' != *dirName) { + std_strlcpy(absName, dirName, absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, name, absNameLen); + } else { + std_strlcpy(absName, name, absNameLen); + } + + nErr = apps_std_fopen(absName, mode, psout); + FREEIF(absName); + if (AEE_SUCCESS == nErr) { + // Success + goto bail; + } + } + domain = get_domain_id() & DOMAIN_ID_MASK; + +#ifdef ANDROID_P + absNameLen = std_strlen("/vendor/dsp/adsp/") + std_strlen(name) + 1; + VERIFYC(NULL != (absName = (char*)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); + + if (domain == ADSP_DOMAIN_ID){ + std_strlcpy(absName, "/vendor/dsp/adsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else if (domain == MDSP_DOMAIN_ID){ + std_strlcpy(absName, "/vendor/dsp/mdsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else if (domain == SDSP_DOMAIN_ID){ + std_strlcpy(absName, "/vendor/dsp/sdsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else if (domain == CDSP_DOMAIN_ID) { + std_strlcpy(absName, "/vendor/dsp/cdsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else { + absName[0] = '\0'; + } + nErr = apps_std_fopen(absName, mode, psout); +#else + absNameLen = std_strlen("/dsp/adsp/") + std_strlen(name) + 1; + VERIFYC(NULL != (absName = (char*)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); + + if (domain == ADSP_DOMAIN_ID){ + std_strlcpy(absName, "/dsp/adsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else if (domain == MDSP_DOMAIN_ID){ + std_strlcpy(absName, "/dsp/mdsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else if (domain == SDSP_DOMAIN_ID){ + std_strlcpy(absName, "/dsp/sdsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else if (domain == CDSP_DOMAIN_ID) { + std_strlcpy(absName, "/dsp/cdsp/", absNameLen); + std_strlcat(absName, name,absNameLen); + } else { + absName[0] = '\0'; + } + nErr = apps_std_fopen(absName, mode, psout); +#endif +bail: + FREEIF(absName); + FREEIF(dirListBuf); + if (nErr != AEE_SUCCESS) { + VERIFY_IPRINTF("Error %x: fopen failed for %s. (%s)", nErr, name, strerror(ERRNO)); + } + return nErr; +} + +__QAIC_HEADER_EXPORT int __QAIC_IMPL(apps_std_get_search_paths_with_env)( + const char* envvarname, const char* delim, _cstring1_t* paths, + int pathsLen, uint32* numPaths, uint16* maxPathLen) __QAIC_IMPL_ATTRIBUTE{ + + char *path = NULL; + int nErr = AEE_SUCCESS; + char *dirListBuf = NULL; + int i = 0; + char *saveptr = NULL; + struct stat st; + + VERIFYC(NULL != numPaths, AEE_EBADSIZE); + VERIFYC(NULL != delim, AEE_EINVALIDFORMAT); + VERIFYC(NULL != maxPathLen, AEE_EBADSIZE); + + VERIFY(AEE_SUCCESS == (nErr = get_dirlist_from_env(envvarname, &dirListBuf ))); + + *numPaths = 0; + *maxPathLen = 0; + + // Get the number of folders + path = strtok_r (dirListBuf, delim, &saveptr); + while (path != NULL){ + // If the path exists, add it to the return + if ((stat(path, &st) == 0) && (S_ISDIR(st.st_mode))) { + *maxPathLen = STD_MAX(*maxPathLen, std_strlen(path)+1); + if (paths && i < pathsLen && paths[i].data && paths[i].dataLen >= std_strlen(path)) { + std_strlcpy(paths[i].data, path, paths[i].dataLen); + } + i++; + } + path = strtok_r (NULL, delim, &saveptr); + } + *numPaths = i; + +bail: + FREEIF(dirListBuf); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: apps_std_get_search_paths_with_env failed\n", nErr); + } + return nErr; +} + + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fgets)(apps_std_FILE sin, byte* buf, int bufLen, int* bEOF) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + char* out = fgets((char*)buf, bufLen, sinfo->u.stream); + *bEOF = FALSE; + if(!out) { + int err; + if(0 != (err = ferror(sinfo->u.stream))) { + nErr = AEE_EFGETS; + VERIFY_EPRINTF("Error %x: fgets failed for %x, errno is %s\n", nErr, sin, strerror(ERRNO)); + return nErr; + } + *bEOF = feof(sinfo->u.stream); + } + } else { + nErr = AEE_EUNSUPPORTED; + } +bail: + return nErr; +} + +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fileExists)(const char* path, boolean* exists) __QAIC_HEADER_ATTRIBUTE{ + int nErr = AEE_SUCCESS; + struct stat buffer; + + VERIFYC(path != NULL, AEE_EMEMPTR); + VERIFYC(exists != NULL, AEE_EMEMPTR); + + *exists = (stat (path, &buffer) == 0); + +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: fileExists failed for path %s\n", nErr, path); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fsync)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info* sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + // This flushes the given sin file stream to user-space buffer. + // NOTE: this does NOT ensure data is physically sotred on disk + nErr = fflush(sinfo->u.stream); + if(nErr != AEE_SUCCESS){ + VERIFY_EPRINTF("Error %x: apps_std fsync failed,errno is %s\n", nErr, strerror(ERRNO)); + } + } else { + nErr = AEE_EUNSUPPORTED; + } + +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fremove)(const char* name) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if(NULL == name){ + return nErr; + } + nErr = remove(name); + if(nErr != AEE_SUCCESS){ + VERIFY_EPRINTF("Error %x: failed to remove file %s,errno is %s\n", nErr, name, strerror(ERRNO)); + } + + return nErr; +} + +static int decrypt_int(char* fbuf, int size) { + int nErr = 0, fd; + void* handle = 0; + int32_t (*l_init)(void); + int32_t (*l_deinit)(void); + int32_t (*l_decrypt)(int32_t, int32_t); + + VERIFYC(NULL != (handle = dlopen("liblmclient.so", RTLD_NOW)), AEE_EBADHANDLE); + VERIFYC(NULL != (l_init = dlsym(handle, "license_manager_init")), AEE_ENOSUCHSYMBOL); + VERIFYC(NULL != (l_deinit = dlsym(handle, "license_manager_deinit")), AEE_ENOSUCHSYMBOL); + VERIFYC(NULL != (l_decrypt = dlsym(handle, "license_manager_decrypt")), AEE_ENOSUCHSYMBOL); + VERIFY(0 == (nErr = l_init())); + VERIFY(-1 != (fd = rpcmem_to_fd_internal(fbuf))); + VERIFY(0 == (nErr = l_decrypt(fd, size))); + VERIFY(0 == (nErr = l_deinit())); +bail: + if(nErr) { + VERIFY_EPRINTF("Error %x: dlopen for licmgr failed. errno: %s\n", nErr, dlerror()); + } + if(handle) { + dlclose(handle); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fdopen_decrypt)(apps_std_FILE sin, apps_std_FILE *psout) __QAIC_IMPL_ATTRIBUTE { + int fd, nErr = AEE_SUCCESS; + struct stat st_buf; + struct apps_std_info* sinfo = 0; + int sz, pos; + char* fbuf = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if(sinfo->type == APPS_STD_STREAM_FILE) { + pos = ftell(sinfo->u.stream); + VERIFYC(-1 != (fd = fileno(sinfo->u.stream)), AEE_EFLEN); + VERIFYC(0 == fstat(fd, &st_buf), AEE_EFLEN); + sz = (int)st_buf.st_size; + VERIFYC(0 != (fbuf = rpcmem_alloc_internal(ION_HEAP_ID_QSEECOM, 1, sz)), AEE_EMEMPTR); + VERIFYC(0 == fseek(sinfo->u.stream, 0, SEEK_SET), AEE_EFSEEK); + VERIFYC(sz == (int)fread(fbuf, 1, sz, sinfo->u.stream), AEE_EFREAD); + VERIFY(0 == (nErr = decrypt_int(fbuf, sz))); + apps_std_FILE_set_buffer_stream(sinfo, fbuf, sz, pos); + *psout = sin; + } else { + nErr = AEE_EUNSUPPORTED; + } +bail: + if(nErr) { + if(fbuf) { + rpcmem_free_internal(fbuf); + fbuf = NULL; + } + } + return nErr; +} + + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_opendir)(const char* name, apps_std_DIR* dir) __QAIC_IMPL_ATTRIBUTE { + int nErr = 0; + DIR *odir; + + if(NULL == dir) { + return AEE_EBADPARM; + } + odir = opendir(name); + if(odir != NULL) { + dir->handle = (uint64)odir; + } else { + nErr = -1; + VERIFY_EPRINTF("Error %x: failed to opendir %s,errno is %s\n", nErr, name, strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_closedir)(const apps_std_DIR* dir) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if((NULL == dir) || (0 == dir->handle)){ + return AEE_EBADPARM; + } + nErr = closedir((DIR *)dir->handle); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: failed to closedir, errno is %s\n", nErr, strerror(ERRNO)); + } + + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_readdir)(const apps_std_DIR* dir, apps_std_DIRENT* dirent, int *bEOF) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct dirent *odirent; + + if((NULL == dir) || (0 == dir->handle)){ + return AEE_EBADPARM; + } + *bEOF = 0; + errno = 0; + odirent = readdir((DIR *)dir->handle); + if(odirent != NULL) { + dirent->ino = (int)odirent->d_ino; + std_strlcpy(dirent->name, odirent->d_name, sizeof(dirent->name)); + } else { + if(errno == 0) { + *bEOF = 1; + } else { + nErr = -1; + } + } + + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_mkdir)(const char* name, int mode) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if(NULL == name){ + return nErr; + } + nErr = mkdir(name, mode); + if(nErr != AEE_SUCCESS){ + VERIFY_EPRINTF("Error %x: failed to mkdir %s,errno is %s\n", nErr, name, strerror(ERRNO)); + } + + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_rmdir)(const char* name) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if(NULL == name){ + return nErr; + } + nErr = rmdir(name); + if(nErr != AEE_SUCCESS){ + VERIFY_EPRINTF("Error %x: failed to rmdir %s,errno is %s\n", nErr, name, strerror(ERRNO)); + } + + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_stat)(const char* name, apps_std_STAT* ist) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS, nOpenErr = AEE_SUCCESS, fd = -1; + apps_std_FILE ps; + struct apps_std_info* sinfo = 0; + struct stat st; + + if((NULL == name) || (NULL == ist)) { + return AEE_EBADPARM; + } + VERIFYC(0 == (nOpenErr = apps_std_fopen_with_env("ADSP_LIBRARY_PATH", ";", name, "r", &ps)), AEE_EFOPEN); + VERIFYC(0 == (nErr = apps_std_FILE_get(ps, &sinfo)), AEE_EBADFD); + VERIFYC(-1 != (fd = fileno(sinfo->u.stream)), AEE_EBADFD); + VERIFYC(0 == fstat(fd, &st), AEE_EBADFD); + ist->dev = st.st_dev; + ist->ino = st.st_ino; + ist->mode = st.st_mode; + ist->nlink = st.st_nlink; + ist->rdev = st.st_rdev; + ist->size = st.st_size; + ist->atime = (int64)st.st_atim.tv_sec; + ist->atimensec = (int64)st.st_atim.tv_nsec; + ist->mtime = (int64)st.st_mtim.tv_sec; + ist->mtimensec =(int64)st.st_mtim.tv_nsec; + ist->ctime = (int64)st.st_ctim.tv_nsec; + ist->ctimensec = (int64)st.st_ctim.tv_nsec; +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: failed to stat %s, file open returned %x, errno is %s\n", nErr, name, nOpenErr, strerror(ERRNO)); + } + if (nOpenErr == AEE_SUCCESS) { + apps_std_fclose(ps); + sinfo = 0; + } + if(sinfo) { + apps_std_FILE_free(sinfo); + } + return nErr; +} + +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_ftrunc)(apps_std_FILE sin, int offset) __QAIC_HEADER_ATTRIBUTE { + int nErr = 0, fd = -1; + struct apps_std_info* sinfo = 0; + + VERIFYC(0 == (nErr = apps_std_FILE_get(sin, &sinfo)), AEE_EBADFD); + VERIFYC(-1 != (fd = fileno(sinfo->u.stream)), AEE_EBADFD); + + if(0 != ftruncate(fd, offset)) { + return ERRNO; + } +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_frename)(const char* oldname, const char* newname) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + VERIFYC(NULL != oldname && NULL != newname, AEE_EBADPARM); + nErr = rename(oldname, newname); +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: failed to rename file, errno is %s\n", nErr, strerror(ERRNO)); + } + return nErr; +} diff --git a/src/apps_std_skel.c b/src/apps_std_skel.c new file mode 100644 index 0000000..19944cb --- /dev/null +++ b/src/apps_std_skel.c @@ -0,0 +1,1227 @@ +#ifndef _APPS_STD_SKEL_H +#define _APPS_STD_SKEL_H +/* + * 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 "apps_std.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#include <string.h> +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _APPS_STD_SLIM_H +#define _APPS_STD_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[7]; +static const Type* const typeArrays[15] = {&(types[2]),&(types[2]),&(types[2]),&(types[5]),&(types[5]),&(types[2]),&(types[2]),&(types[6]),&(types[6]),&(types[6]),&(types[6]),&(types[6]),&(types[6]),&(types[3]),&(types[4])}; +static const StructType structTypes[3] = {{0x1,&(typeArrays[0]),0x8,0x0,0x8,0x8,0x1,0x8},{0x2,&(typeArrays[13]),0x104,0x0,0x104,0x4,0x1,0x4},{0xd,&(typeArrays[0]),0x60,0x0,0x60,0x8,0x1,0x8}}; +static const SequenceType sequenceTypes[1] = {{&(types[1]),0x0,0x4,0x4,0x0}}; +static const Type types[7] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8)},{0x8,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x8},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4},{0xff,{{(const uintptr_t)&(types[0]),(const uintptr_t)0xff}}, 8,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8}}; +static const Parameter parameters[16] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{0,0}}, 3,0x4,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x8,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,3,0},{0x2,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x2,3,0},{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1,3,0},{0x8,{{(const uintptr_t)&(structTypes[0]),0}}, 6,0x8,3,0},{0x8,{{(const uintptr_t)&(structTypes[0]),0}}, 6,0x8,0,0},{0x104,{{(const uintptr_t)&(structTypes[1]),0}}, 6,0x4,3,0},{0x60,{{(const uintptr_t)&(structTypes[2]),0}}, 6,0x8,3,0}}; +static const Parameter* const parameterArrays[44] = {(&(parameters[0])),(&(parameters[0])),(&(parameters[8])),(&(parameters[9])),(&(parameters[10])),(&(parameters[0])),(&(parameters[0])),(&(parameters[0])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[4])),(&(parameters[1])),(&(parameters[1])),(&(parameters[2])),(&(parameters[3])),(&(parameters[1])),(&(parameters[1])),(&(parameters[2])),(&(parameters[0])),(&(parameters[0])),(&(parameters[1])),(&(parameters[13])),(&(parameters[14])),(&(parameters[1])),(&(parameters[0])),(&(parameters[0])),(&(parameters[2])),(&(parameters[0])),(&(parameters[7])),(&(parameters[1])),(&(parameters[2])),(&(parameters[2])),(&(parameters[5])),(&(parameters[0])),(&(parameters[15])),(&(parameters[0])),(&(parameters[12])),(&(parameters[0])),(&(parameters[11])),(&(parameters[2])),(&(parameters[6])),(&(parameters[2])),(&(parameters[1]))}; +static const Method methods[23] = {{REMOTE_SCALARS_MAKEX(0,0,0x3,0x1,0x0,0x0),0x8,0x4,3,3,(&(parameterArrays[7])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x3,0x1,0x0,0x0),0xc,0x4,4,4,(&(parameterArrays[18])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[10])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x8,6,4,(&(parameterArrays[14])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x8,0x8,5,4,(&(parameterArrays[10])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[14])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x8,0x0,3,2,(&(parameterArrays[10])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x4,2,2,(&(parameterArrays[42])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0xc,0x0,3,3,(&(parameterArrays[31])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x8,2,2,(&(parameterArrays[40])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[28])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x3,0x0,0x0,0x0),0xc,0x0,3,3,(&(parameterArrays[25])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x5,0x1,0x0,0x0),0x10,0x4,5,5,(&(parameterArrays[5])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0xc,0x6,7,5,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x4,0x1,2,2,(&(parameterArrays[38])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x4,0x8,2,2,(&(parameterArrays[36])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,1,1,(&(parameterArrays[22])),0x8,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x8,0x108,3,3,(&(parameterArrays[22])),0x8,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[26])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x4,0x60,2,2,(&(parameterArrays[34])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[31])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x3,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[0])),0x4,0x0}}; +static const Method* const methodArrays[34] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[5]),&(methods[6]),&(methods[7]),&(methods[8]),&(methods[9]),&(methods[2]),&(methods[7]),&(methods[7]),&(methods[2]),&(methods[10]),&(methods[11]),&(methods[12]),&(methods[10]),&(methods[13]),&(methods[5]),&(methods[14]),&(methods[15]),&(methods[2]),&(methods[10]),&(methods[7]),&(methods[16]),&(methods[17]),&(methods[18]),&(methods[19]),&(methods[10]),&(methods[20]),&(methods[21]),&(methods[22])}; +static const char strings[530] = "get_search_paths_with_env\0fdopen_decrypt\0fopen_with_env\0print_string\0bytesWritten\0fileExists\0maxPathLen\0envvarname\0ctimensec\0mtimensec\0atimensec\0valLenReq\0posLenReq\0bytesRead\0closedir\0numPaths\0unsetenv\0override\0clearerr\0newname\0oldname\0frename\0readdir\0opendir\0fremove\0fsetpos\0fgetpos\0freopen\0ftrunc\0dirent\0handle\0exists\0getenv\0ferror\0rewind\0whence\0offset\0fwrite\0fclose\0fflush\0ctime\0mtime\0atime\0nlink\0rmdir\0mkdir\0fsync\0paths\0fgets\0delim\0fseek\0ftell\0fread\0psout\0fopen\0size\0rdev\0stat\0path\0feof\0flen\0bEOF\0mode\0tsz\0ino\0val\0str\0buf\0sin\0"; +static const uint16_t methodStrings[129] = {476,110,476,506,472,510,501,394,471,466,388,135,382,125,376,115,244,180,306,299,510,110,496,0,104,430,418,184,93,41,104,430,110,501,454,355,526,522,69,496,448,526,522,165,496,284,526,110,501,454,252,110,180,306,424,526,522,496,195,110,514,202,320,110,514,145,436,526,348,341,276,526,272,155,460,110,501,454,236,228,220,292,526,348,406,110,501,175,180,306,26,526,454,82,481,313,327,526,216,486,526,496,491,526,492,442,526,272,268,526,272,400,110,260,110,412,526,193,110,56,518,211,526,334,526,362,526,369,526}; +static const uint16_t methodStringsArrays[34] = {74,45,127,125,40,35,70,108,105,66,102,123,99,96,121,119,62,58,117,29,54,23,93,115,113,90,50,87,16,84,111,0,81,78}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(apps_std_slim) = {34,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_APPS_STD_SLIM_H +extern int adsp_mmap_fd_getinfo(int, uint32_t *); +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _skel_method(int (*_pfn)(char*, char*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + char* _in2[1]; + uint32_t _in2Len[1]; + uint32_t* _primIn; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((3 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, (int)((_praIn[1].buf.nLen / 1)) >= (int)(_in2Len[0])); + _in2[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in1, *_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_1(int (*_pfn)(uint32_t, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t _in1[1]; + uint32_t _in2[1]; + uint32_t* _primIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn(*_in1, *_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_2(int (*_pfn)(char*, uint64_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + uint64_t _rout2[12]; + uint32_t* _primIn; + int _numIn[1]; + uint64_t* _primROut; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 96); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in1, _rout2)); + _COPY(_primROut, 0, _rout2, 0, 96); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_invoke(uint32_t _mid, uint32_t _sc, remote_arg* _pra) { + switch(_mid) + { + case 31: + return _skel_method_2((void*)__QAIC_IMPL(apps_std_stat), _sc, _pra); + case 32: + return _skel_method_1((void*)__QAIC_IMPL(apps_std_ftrunc), _sc, _pra); + case 33: + return _skel_method((void*)__QAIC_IMPL(apps_std_frename), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +static __inline int _skel_method_3(int (*_pfn)(char*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + uint32_t* _primIn; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in0)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_4(int (*_pfn)(char*, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + uint32_t _in1[1]; + uint32_t* _primIn; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn(*_in0, *_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_5(int (*_pfn)(uint64_t*, uint32_t*, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint64_t _in0[1]; + uint32_t _rout1[65]; + uint32_t _rout2[1]; + uint64_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 264); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _TRY(_nErr, _pfn(_in0, _rout1, _rout2)); + _COPY(_primROut, 0, _rout1, 0, 260); + _COPY(_primROut, 260, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_6(int (*_pfn)(uint64_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint64_t _in0[1]; + uint64_t* _primIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _TRY(_nErr, _pfn(_in0)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_7(int (*_pfn)(char*, uint64_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + uint64_t _rout1[1]; + uint32_t* _primIn; + int _numIn[1]; + uint64_t* _primROut; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in0, _rout1)); + _COPY(_primROut, 0, _rout1, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_8(int (*_pfn)(uint32_t, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t _rout1[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _TRY(_nErr, _pfn(*_in0, _rout1)); + _COPY(_primROut, 0, _rout1, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_9(int (*_pfn)(uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t* _primIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _TRY(_nErr, _pfn(*_in0)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_10(int (*_pfn)(char*, uint8_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + uint8_t _rout1[1]; + uint32_t* _primIn; + int _numIn[1]; + uint8_t* _primROut; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 1); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in0, _rout1)); + _COPY(_primROut, 0, _rout1, 0, 1); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_pack(remote_arg* _praROutPost, remote_arg* _ppraROutPost[1], void* _primROut, char* _rout0[1], uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _skel_unpack(_allocator* _al, remote_arg* _praIn, remote_arg* _ppraIn[1], remote_arg* _praROut, remote_arg* _ppraROut[1], remote_arg* _praHIn, remote_arg* _ppraHIn[1], remote_arg* _praHROut, remote_arg* _ppraHROut[1], void* _primIn, void* _primROut, char* _rout0[1], uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_rout0Len, 0, _primIn, 0, 4); + _ASSERT(_nErr, (int)((_praROut[0].buf.nLen / 1)) >= (int)(_rout0Len[0])); + _rout0[0] = _praROut[0].buf.pv; + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_11(int (*_pfn)(char*, char*, void*, uint32_t, uint32_t*, uint16_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + void* _rout2[1]; + uint32_t _rout2Len[1]; + uint32_t _rout3[1]; + uint16_t _rout4[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + int _numInH[1]; + int _numROut[1]; + remote_arg* _praIn; + remote_arg* _praROut; + remote_arg* _praROutPost; + remote_arg** _ppraROutPost = &_praROutPost; + _allocator _al[1] = {{0}}; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn2; + char* _seq_nat2; + int _ii; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((4 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 6); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _numInH[0] = REMOTE_SCALARS_INHANDLES(_sc); + _numROut[0] = REMOTE_SCALARS_OUTBUFS(_sc); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROutPost = _praROut; + _COPY(_in0Len, 0, _primIn, 0, 4); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, (int)((_praIn[1].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_rout2Len, 0, _primIn, 8, 4); + _allocator_init(_al, 0, 0); + if(_praHIn == 0) + { + _praHIn = ((_praROut + _numROut[0]) + 1); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ASSERT(_nErr, (int)((_praIn[2].buf.nLen / 4)) >= (int)(_rout2Len[0])); + _ALLOCATE(_nErr, _al, (_rout2Len[0] * SLIM_IFPTR32(8, 16)), SLIM_IFPTR32(4, 8), _rout2[0]); + for(_ii = 0, _seq_primIn2 = (char*)_praIn[2].buf.pv, _seq_nat2 = (char*)_rout2[0];_ii < (int)_rout2Len[0];++_ii, _seq_primIn2 = (_seq_primIn2 + 4), _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _skel_unpack(_al, (_praIn + 3), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn2, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _TRY(_nErr, _pfn(*_in0, *_in1, *_rout2, *_rout2Len, _rout3, _rout4)); + for(_ii = 0, _seq_nat2 = (char*)_rout2[0];_ii < (int)_rout2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _skel_pack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _COPY(_primROut, 0, _rout3, 0, 4); + _COPY(_primROut, 4, _rout4, 0, 2); + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +static __inline int _skel_method_12(int (*_pfn)(uint32_t, char*, uint32_t, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _rout1[1]; + uint32_t _rout1Len[1]; + uint32_t _rout2[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, (int)((_praROut[0].buf.nLen / 1)) >= (int)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, *_rout1, *_rout1Len, _rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_13(int (*_pfn)(char*, char*, char*, char*, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + char* _in2[1]; + uint32_t _in2Len[1]; + char* _in3[1]; + uint32_t _in3Len[1]; + uint32_t _rout4[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((5 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 16); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, (int)((_praIn[1].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, (int)((_praIn[2].buf.nLen / 1)) >= (int)(_in2Len[0])); + _in2[0] = _praIn[2].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _COPY(_in3Len, 0, _primIn, 12, 4); + _ASSERT(_nErr, (int)((_praIn[3].buf.nLen / 1)) >= (int)(_in3Len[0])); + _in3[0] = _praIn[3].buf.pv; + _ASSERT(_nErr, (_in3Len[0] > 0) && (_in3[0][(_in3Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in0, *_in1, *_in2, *_in3, _rout4)); + _COPY(_primROut, 0, _rout4, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_14(int (*_pfn)(char*, char*, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + uint32_t _in2[1]; + uint32_t* _primIn; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((3 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, (int)((_praIn[1].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn(*_in0, *_in1, *_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_15(int (*_pfn)(char*, char*, uint32_t, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + char* _rout1[1]; + uint32_t _rout1Len[1]; + uint32_t _rout2[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, (int)((_praROut[0].buf.nLen / 1)) >= (int)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, *_rout1, *_rout1Len, _rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_16(int (*_pfn)(uint32_t, uint64_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint64_t _rout1[1]; + uint32_t* _primIn; + int _numIn[1]; + uint64_t* _primROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _TRY(_nErr, _pfn(*_in0, _rout1)); + _COPY(_primROut, 0, _rout1, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_17(int (*_pfn)(uint32_t, uint32_t, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + uint32_t _in1[1]; + uint32_t _in2[1]; + uint32_t* _primIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn(*_in0, *_in1, *_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_18(int (*_pfn)(uint32_t, char*, uint32_t), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + uint32_t* _primIn; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, *_in1, *_in1Len)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_19(int (*_pfn)(uint32_t, char*, uint32_t, uint32_t*, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + uint32_t _rout2[1]; + uint32_t _rout3[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, *_in1, *_in1Len, _rout2, _rout3)); + _COPY(_primROut, 0, _rout2, 0, 4); + _COPY(_primROut, 4, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_20(int (*_pfn)(uint32_t, char*, uint32_t, uint32_t*, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _rout1[1]; + uint32_t _rout1Len[1]; + uint32_t _rout2[1]; + uint32_t _rout3[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((1 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, (int)((_praROut[0].buf.nLen / 1)) >= (int)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn(*_in0, *_rout1, *_rout1Len, _rout2, _rout3)); + _COPY(_primROut, 0, _rout2, 0, 4); + _COPY(_primROut, 4, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_21(int (*_pfn)(uint32_t, char*, char*, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + uint32_t _in0[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + char* _in2[1]; + uint32_t _in2Len[1]; + uint32_t _rout3[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((3 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, (int)((_praIn[1].buf.nLen / 1)) >= (int)(_in2Len[0])); + _in2[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in0, *_in1, *_in2, _rout3)); + _COPY(_primROut, 0, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_22(int (*_pfn)(char*, char*, uint32_t*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd; + char* _in0[1]; + uint32_t _in0Len[1]; + char* _in1[1]; + uint32_t _in1Len[1]; + uint32_t _rout2[1]; + uint32_t* _primIn; + int _numIn[1]; + uint32_t* _primROut; + remote_arg* _praIn; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, (_pra + ((3 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, (int)((_praIn[0].buf.nLen / 1)) >= (int)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, (int)((_praIn[1].buf.nLen / 1)) >= (int)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn(*_in0, *_in1, _rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(apps_std_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method_22((void*)__QAIC_IMPL(apps_std_fopen), _sc, _pra); + case 1: + return _skel_method_21((void*)__QAIC_IMPL(apps_std_freopen), _sc, _pra); + case 2: + return _skel_method_9((void*)__QAIC_IMPL(apps_std_fflush), _sc, _pra); + case 3: + return _skel_method_9((void*)__QAIC_IMPL(apps_std_fclose), _sc, _pra); + case 4: + return _skel_method_20((void*)__QAIC_IMPL(apps_std_fread), _sc, _pra); + case 5: + return _skel_method_19((void*)__QAIC_IMPL(apps_std_fwrite), _sc, _pra); + case 6: + return _skel_method_12((void*)__QAIC_IMPL(apps_std_fgetpos), _sc, _pra); + case 7: + return _skel_method_18((void*)__QAIC_IMPL(apps_std_fsetpos), _sc, _pra); + case 8: + return _skel_method_8((void*)__QAIC_IMPL(apps_std_ftell), _sc, _pra); + case 9: + return _skel_method_17((void*)__QAIC_IMPL(apps_std_fseek), _sc, _pra); + case 10: + return _skel_method_16((void*)__QAIC_IMPL(apps_std_flen), _sc, _pra); + case 11: + return _skel_method_9((void*)__QAIC_IMPL(apps_std_rewind), _sc, _pra); + case 12: + return _skel_method_8((void*)__QAIC_IMPL(apps_std_feof), _sc, _pra); + case 13: + return _skel_method_8((void*)__QAIC_IMPL(apps_std_ferror), _sc, _pra); + case 14: + return _skel_method_9((void*)__QAIC_IMPL(apps_std_clearerr), _sc, _pra); + case 15: + return _skel_method_3((void*)__QAIC_IMPL(apps_std_print_string), _sc, _pra); + case 16: + return _skel_method_15((void*)__QAIC_IMPL(apps_std_getenv), _sc, _pra); + case 17: + return _skel_method_14((void*)__QAIC_IMPL(apps_std_setenv), _sc, _pra); + case 18: + return _skel_method_3((void*)__QAIC_IMPL(apps_std_unsetenv), _sc, _pra); + case 19: + return _skel_method_13((void*)__QAIC_IMPL(apps_std_fopen_with_env), _sc, _pra); + case 20: + return _skel_method_12((void*)__QAIC_IMPL(apps_std_fgets), _sc, _pra); + case 21: + return _skel_method_11((void*)__QAIC_IMPL(apps_std_get_search_paths_with_env), _sc, _pra); + case 22: + return _skel_method_10((void*)__QAIC_IMPL(apps_std_fileExists), _sc, _pra); + case 23: + return _skel_method_9((void*)__QAIC_IMPL(apps_std_fsync), _sc, _pra); + case 24: + return _skel_method_3((void*)__QAIC_IMPL(apps_std_fremove), _sc, _pra); + case 25: + return _skel_method_8((void*)__QAIC_IMPL(apps_std_fdopen_decrypt), _sc, _pra); + case 26: + return _skel_method_7((void*)__QAIC_IMPL(apps_std_opendir), _sc, _pra); + case 27: + return _skel_method_6((void*)__QAIC_IMPL(apps_std_closedir), _sc, _pra); + case 28: + return _skel_method_5((void*)__QAIC_IMPL(apps_std_readdir), _sc, _pra); + case 29: + return _skel_method_4((void*)__QAIC_IMPL(apps_std_mkdir), _sc, _pra); + case 30: + return _skel_method_3((void*)__QAIC_IMPL(apps_std_rmdir), _sc, _pra); + case 31: + { + uint32_t* _mid; + if(REMOTE_SCALARS_INBUFS(_sc) < 1 || _pra[0].buf.nLen < 4) { return AEE_EBADPARM; } + _mid = (uint32_t*)_pra[0].buf.pv; + return _skel_invoke(*_mid, _sc, _pra); + } + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_APPS_STD_SKEL_H diff --git a/src/atomic.c b/src/atomic.c new file mode 100644 index 0000000..cfe1067 --- /dev/null +++ b/src/atomic.c @@ -0,0 +1,68 @@ +/* + * 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 "AEEatomic.h" + +uint32 atomic_Add(uint32 * volatile puDest, int nAdd) { + uint32 previous; + uint32 current; + do { + current = *puDest; + previous = atomic_CompareAndExchange(puDest, current + nAdd, current); + } while(previous != current); + return (current + nAdd); +} + +uint32 atomic_Exchange(uint32* volatile puDest, uint32 uVal) { + uint32 previous; + uint32 current; + do { + current = *puDest; + previous = atomic_CompareAndExchange(puDest, uVal, current); + } while(previous != current); + return previous; +} + +uint32 atomic_CompareOrAdd(uint32* volatile puDest, uint32 uCompare, int nAdd) { + uint32 previous; + uint32 current; + uint32 result; + do { + current = *puDest; + previous = current; + result = current; + if(current != uCompare) { + previous = atomic_CompareAndExchange(puDest, current + nAdd, current); + if(previous == current) { + result = current + nAdd; + } + } + } while(previous != current); + return result; +} + diff --git a/src/cae.c b/src/cae.c new file mode 100644 index 0000000..2711170 --- /dev/null +++ b/src/cae.c @@ -0,0 +1,88 @@ +/* + * 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 "AEEatomic.h" + +#ifdef _WIN32 +#include "Windows.h" +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) { + C_ASSERT(sizeof(LONG) == sizeof(uint32)); + return (uint32)InterlockedCompareExchange((LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) { + C_ASSERT(sizeof(uintptr_t) == sizeof(void*)); + return (uintptr_t)InterlockedCompareExchangePointer((void**)puDest, (void*)uExchange, (void*)uCompare); +} +#elif __hexagon__ + +#ifndef C_ASSERT +#define C_ASSERT(test) \ + switch(0) {\ + case 0:\ + case test:;\ + } +#endif + +static inline unsigned int +qurt_atomic_compare_val_and_set(unsigned int* target, + unsigned int old_val, + unsigned int new_val) +{ + unsigned int current_val; + + __asm__ __volatile__( + "1: %0 = memw_locked(%2)\n" + " p0 = cmp.eq(%0, %3)\n" + " if !p0 jump 2f\n" + " memw_locked(%2, p0) = %4\n" + " if !p0 jump 1b\n" + "2:\n" + : "=&r" (current_val),"+m" (*target) + : "r" (target), "r" (old_val), "r" (new_val) + : "p0"); + + return current_val; +} +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) { + return (uint32)qurt_atomic_compare_val_and_set((unsigned int*)puDest, uCompare, uExchange); +} +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) { + C_ASSERT(sizeof(uintptr_t) == sizeof(uint32)); + return (uint32)atomic_CompareAndExchange((uint32*)puDest, (uint32)uExchange, (uint32)uCompare); +} +#elif __GNUC__ +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +uint64 atomic_CompareAndExchange64(uint64 * volatile puDest, uint64 uExchange, uint64 uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //compare and exchange diff --git a/src/cdsprpcd.c b/src/cdsprpcd.c new file mode 100644 index 0000000..759d297 --- /dev/null +++ b/src/cdsprpcd.c @@ -0,0 +1,71 @@ +/* + * 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. + */ +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_PRINT_ERROR +#endif + +#include <stdio.h> +#include <dlfcn.h> +#include <unistd.h> +#include "verify.h" + + +#ifndef CDSP_DEFAULT_LISTENER_NAME +#define CDSP_DEFAULT_LISTENER_NAME "libcdsp_default_listener.so" +#endif + +typedef int (*adsp_default_listener_start_t)(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + + int nErr = 0; + void *cdsphandler = NULL; + adsp_default_listener_start_t listener_start; + + VERIFY_EPRINTF("cdsp daemon starting"); + while (1) { + if(NULL != (cdsphandler = dlopen(CDSP_DEFAULT_LISTENER_NAME, RTLD_NOW))) { + if(NULL != (listener_start = + (adsp_default_listener_start_t)dlsym(cdsphandler, "adsp_default_listener_start"))) { + VERIFY_IPRINTF("cdsp_default_listener_start called"); + listener_start(argc, argv); + } + if(0 != dlclose(cdsphandler)) { + VERIFY_EPRINTF("dlclose failed"); + } + } else { + VERIFY_EPRINTF("cdsp daemon error %s", dlerror()); + } + VERIFY_EPRINTF("cdsp daemon will restart after 100ms..."); + usleep(100000); + } + VERIFY_EPRINTF("cdsp daemon exiting %x", nErr); +bail: + return nErr; +} diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c new file mode 100644 index 0000000..328dfa0 --- /dev/null +++ b/src/fastrpc_apps_user.c @@ -0,0 +1,1915 @@ +/* +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <errno.h> +#include <pthread.h> + +#define FARF_ERROR 1 +//#define FARF_HIGH 1 +#include "HAP_farf.h" +#include "verify.h" +#include "remote_priv.h" +#include "shared.h" +#include "fastrpc_internal.h" +#include "fastrpc_apps_user.h" +#include "adsp_current_process.h" +#include "adsp_current_process1.h" +#include "adspmsgd_adsp1.h" +#include "remotectl.h" +#include "rpcmem.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "AEEQList.h" +#include "apps_std.h" +#include "platform_libs.h" +#include "fastrpc_perf.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> + +#ifndef _WIN32 +#include <pthread.h> +#include <sys/inotify.h> +#include <sys/eventfd.h> +#include <poll.h> +#include <sys/mman.h> +#endif // __WIN32 + +#ifndef INT_MAX +#define INT_MAX (int)(-1) +#endif + +#define ADSPRPC_DEVICE "/dev/fastrpc-adsp" +#define SDSPRPC_DEVICE "/dev/fastrpc-sdsp" +#define MDSPRPC_DEVICE "/dev/fastrpc-mdsp" +#define CDSPRPC_DEVICE "/dev/fastrpc-cdsp" + +/* Secure and default device nodes */ +#define SECURE_DEVICE "/dev/fastrpc-adsp-secure" +#define DEFAULT_DEVICE "/dev/fastrpc-adsp" + +#define INVALID_DOMAIN_ID -1 +#define INVALID_HANDLE (remote_handle64)(-1) +#define INVALID_KEY (pthread_key_t)(-1) + +#define MAX_DMA_HANDLES 256 + +#define FASTRPC_TRACE_INVOKE_START "fastrpc_trace_invoke_start" +#define FASTRPC_TRACE_INVOKE_END "fastrpc_trace_invoke_end" +#define FASTRPC_TRACE_LOG(k, handle, sc) if(fastrpc_trace == 1 && !IS_STATIC_HANDLE(handle)) { \ + FARF(ALWAYS, "%s: sc 0x%x", (k), (sc)); } \ + +#define FASTRPC_MODE_DEBUG (0x1) +#define FASTRPC_MODE_PTRACE (0x2) +#define FASTRPC_MODE_CRC (0x4) +#define FASTRPC_MODE_ADAPTIVE_QOS (0x10) + +#define FASTRPC_DISABLE_QOS 0 +#define FASTRPC_PM_QOS 1 +#define FASTRPC_ADAPTIVE_QOS 2 + +/* FastRPC mode for Unsigned module */ +#define FASTRPC_MODE_UNSIGNED_MODULE (0x8) + +#define M_CRCLIST (64) +#define IS_DEBUG_MODE_ENABLED(var) (var & FASTRPC_MODE_DEBUG) +#define IS_CRC_CHECK_ENABLED(var) (var & FASTRPC_MODE_CRC) +#define POLY32 0x04C11DB7 // G(x) = x^32+x^26+x^23+x^22+x^16+x^12 + // +x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 + +#define FASTRPC_LATENCY_START (1) +#define FASTRPC_LATENCY_STOP (0) +#define FASTRPC_LATENCY_EXIT (2) +#define FASTRPC_LATENCY_VOTE_ON (1) +#define FASTRPC_LATENCY_VOTE_OFF (0) +#define FASTRPC_LATENCY_WAIT_TIME (1) + +#ifdef ANDROID_P +#define FASTRPC_PROP_PROCESS "vendor.fastrpc.process.attrs" +#define FASTRPC_PROP_TRACE "vendor.fastrpc.debug.trace" +#define FASTRPC_PROP_TESTSIG "vendor.fastrpc.debug.testsig" +#else +#define FASTRPC_PROP_PROCESS "fastrpc.process.attrs" +#define FASTRPC_PROP_TRACE "fastrpc.debug.trace" +#define FASTRPC_PROP_TESTSIG "fastrpc.debug.testsig" +#endif + +#define DEFAULT_UTHREAD_PRIORITY 0xC0 +#define DEFAULT_UTHREAD_STACK_SIZE 16*1024 + +/* Shell prefix for signed and unsigned */ +const char* const SIGNED_SHELL = "fastrpc_shell_"; +const char* const UNSIGNED_SHELL = "fastrpc_shell_unsigned_"; + +struct fastrpc_latency { + int adaptive_qos; + int state; + int exit; + int invoke; + int vote; + int dev; + int wait_time; + int latency; + pthread_t thread; + pthread_mutex_t mut; + pthread_mutex_t wmut; + pthread_cond_t cond; +}; + +struct fastrpc_thread_params { + uint32_t prio; + uint32_t stack_size; + int reqID; + pthread_t thread; +}; + +struct mem_to_fd { + QNode qn; + void* buf; + int size; + int fd; + int nova; + int attr; + int refcount; +}; + +struct mem_to_fd_list { + QList ql; + pthread_mutex_t mut; +}; + +struct dma_handle_info { + int fd; + int len; + int used; + uint32_t attr; +}; + +struct handle_info { + QNode qn; + struct handle_list *hlist; + remote_handle64 local; + remote_handle64 remote; +}; + +struct handle_list { + QList ql; + pthread_mutex_t mut; + pthread_mutex_t init; + int dsppd; + char *dsppdname; + int domainsupport; + int nondomainsupport; + int kmem_support; + int dev; + int initialized; + int setmode; + uint32_t mode; + uint32_t info; + void* pdmem; + remote_handle64 cphandle; + remote_handle64 msghandle; + int procattrs; + struct fastrpc_latency qos; + struct fastrpc_thread_params th_params; + int unsigned_module; +}; + +static struct mem_to_fd_list fdlist; +static struct handle_list *hlist = 0; +static struct dma_handle_info dhandles[MAX_DMA_HANDLES]; +static int dma_handle_count = 0; +static pthread_key_t tlsKey = INVALID_KEY; + +static int fastrpc_trace = 0; + +extern int listener_android_domain_init(int domain); +extern void listener_android_domain_deinit(int domain); +extern int initFileWatcher(int domain); +extern void deinitFileWatcher(int domain); +static int open_dev(int domain); +static void domain_deinit(int domain); +static int __attribute__((constructor)) fastrpc_init_once(void); +remote_handle64 get_adsp_current_process1_handle(int domain); +remote_handle64 get_adspmsgd_adsp1_handle(int domain); +static int remote_unmap_fd(void *buf, int size, int fd, int attr); + +static uint32_t crc_table[256]; + +static void GenCrc32Tab(uint32_t GenPoly, uint32_t *crctab) +{ + uint32_t crc; + int i, j; + + for (i = 0; i < 256; i++) { + crc = i<<24; + for (j = 0; j <8; j++) { + crc = (crc << 1) ^ (crc & 0x80000000 ? GenPoly : 0); + } + crctab[i] = crc; + } +} + +static uint32_t crc32_lut(unsigned char *data, int nbyte, uint32_t *crctab) +{ + uint32_t crc = 0; + if (!data || !crctab) + return 0; + + while(nbyte--) { + crc = (crc<<8) ^ crctab[(crc>>24) ^ *data++]; + } + return crc; +} + +int fastrpc_latency_refinc(struct fastrpc_latency *qp) { + int nErr = 0; + + if (qp == NULL || qp->state == FASTRPC_LATENCY_STOP) + goto bail; + qp->invoke++; + if (qp->vote == FASTRPC_LATENCY_VOTE_OFF) { + pthread_mutex_lock(&qp->wmut); + pthread_cond_signal(&qp->cond); + pthread_mutex_unlock(&qp->wmut); + } +bail: + return 0; +} + +static void* fastrpc_latency_thread_handler(void* arg) { + FARF(ALWAYS, "Unsupported: rpc latency thread exited"); + return NULL; +} + +int fastrpc_latency_init(int dev, struct fastrpc_latency *qos) { + int i, nErr = 0; + + VERIFY(qos && dev != -1); + + qos->dev = dev; + qos->state = FASTRPC_LATENCY_STOP; + qos->thread = 0; + qos->wait_time = FASTRPC_LATENCY_WAIT_TIME; + pthread_mutex_init(&qos->mut, 0); + pthread_mutex_init(&qos->wmut, 0); + pthread_cond_init(&qos->cond, NULL); +bail: + return nErr; +} + +int fastrpc_latency_deinit(struct fastrpc_latency *qos) { + int nErr = 0; + + VERIFY(qos); + if (qos->state == FASTRPC_LATENCY_START) { + pthread_mutex_lock(&qos->wmut); + qos->exit = FASTRPC_LATENCY_EXIT; + pthread_cond_signal(&qos->cond); + pthread_mutex_unlock(&qos->wmut); + if(qos->thread) { + pthread_join(qos->thread, 0); + qos->thread = 0; + FARF(ALWAYS, "latency thread joined"); + } + qos->state = FASTRPC_LATENCY_STOP; + pthread_mutex_destroy(&qos->mut); + pthread_mutex_destroy(&qos->wmut); + } +bail: + return 0; +} + +/* Thread function that will be invoked to update remote user PD parameters */ +static void *fastrpc_set_remote_uthread_params(void *arg) +{ + int nErr = AEE_SUCCESS, paramsLen = 2; + struct fastrpc_thread_params *th_params = (struct fastrpc_thread_params*)arg; + + VERIFY(th_params != NULL); + VERIFY(AEE_SUCCESS == (nErr = remotectl_set_param(th_params->reqID, (uint32_t*)th_params, paramsLen))); +bail: + if (nErr != AEE_SUCCESS) + FARF(ERROR, "Error 0x%x: setting remote user thread parameters failed !", nErr); + return NULL; +} + +void *remote_register_fd_attr(int fd, int size, int attr) { + int nErr = AEE_SUCCESS; + void *po = NULL; + void *buf = (void*)-1; + struct mem_to_fd* tofd = 0; + + VERIFY(!fastrpc_init_once()); + VERIFYC(NULL != (tofd = calloc(1, sizeof(*tofd))), AEE_ENOMEMORY); + QNode_CtorZ(&tofd->qn); + VERIFYC((void*)-1 != (buf = mmap(0, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)), AEE_EMMAP); + tofd->buf = buf; + tofd->size = size; + tofd->fd = fd; + tofd->nova = 1; + tofd->attr = attr; + + pthread_mutex_lock(&fdlist.mut); + QList_AppendNode(&fdlist.ql, &tofd->qn); + pthread_mutex_unlock(&fdlist.mut); + + tofd = 0; + po = buf; + buf = (void*)-1; +bail: + if(buf != (void*)-1) + munmap(buf, size); + if(tofd) + { + free(tofd); + tofd = NULL; + } + if(nErr != AEE_SUCCESS) { + FARF(ERROR,"Error %x: remote register fd fails for fd %x, size %x\n", nErr, fd, size); + } + return po; +} + +void *remote_register_fd(int fd, int size) { + return remote_register_fd_attr(fd, size, 0); +} + +static void remote_register_buf_common(void* buf, int size, int fd, int attr) { + int nErr = 0; + VERIFY(!fastrpc_init_once()); + if(fd != -1) { + struct mem_to_fd* tofd; + int fdfound = 0; + QNode* pn, *pnn; + + pthread_mutex_lock(&fdlist.mut); + QLIST_NEXTSAFE_FOR_ALL(&fdlist.ql, pn, pnn) { + tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if(tofd->buf == buf && tofd->size == size && tofd->fd == fd) { + fdfound = 1; + if(attr) + tofd->attr = attr; + tofd->refcount++; + break; + } + } + pthread_mutex_unlock(&fdlist.mut); + if(!fdfound) { + VERIFYC(NULL != (tofd = calloc(1, sizeof(*tofd))), AEE_ENOMEMORY); + QNode_CtorZ(&tofd->qn); + tofd->buf = buf; + tofd->size = size; + tofd->fd = fd; + if (attr) + tofd->attr = attr; + tofd->refcount++; + pthread_mutex_lock(&fdlist.mut); + QList_AppendNode(&fdlist.ql, &tofd->qn); + pthread_mutex_unlock(&fdlist.mut); + } + } else { + QNode* pn, *pnn; + pthread_mutex_lock(&fdlist.mut); + QLIST_NEXTSAFE_FOR_ALL(&fdlist.ql, pn, pnn) { + struct mem_to_fd* tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if(tofd->buf == buf && tofd->size == size) { + tofd->refcount--; + if(tofd->refcount <= 0) { + QNode_DequeueZ(&tofd->qn); + if (tofd->attr & FASTRPC_ATTR_KEEP_MAP) { + remote_unmap_fd(tofd->buf, tofd->size, tofd->fd, tofd->attr); + } + if(tofd->nova) { + munmap(tofd->buf, tofd->size); + } + free(tofd); + tofd = NULL; + } + break; + } + } + pthread_mutex_unlock(&fdlist.mut); + } +bail: + if(nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: remote_register_buf failed buf %p, size %d, fd %x", nErr, buf, size, fd); + } + return; +} + +void remote_register_buf(void* buf, int size, int fd) { + return remote_register_buf_common(buf, size, fd, 0); +} + +void remote_register_buf_attr(void* buf, int size, int fd, int attr) { + return remote_register_buf_common(buf, size, fd, attr); +} + +int remote_register_dma_handle_attr(int fd, uint32_t len, uint32_t attr) { + int nErr = AEE_SUCCESS, i; + int fd_found = 0; + + if (attr && attr != FASTRPC_ATTR_NOMAP) { + FARF(ERROR, "Error: %s failed, unsupported attribute 0x%x", __func__, attr); + return AEE_EBADPARM; + } + VERIFY(!fastrpc_init_once()); + + pthread_mutex_lock(&fdlist.mut); + for(i = 0; i < dma_handle_count; i++) { + if(dhandles[i].used && dhandles[i].fd == fd) { + /* If fd already present in handle list, then just update attribute only if its zero */ + if(!dhandles[i].attr) { + dhandles[i].attr = attr; + } + fd_found = 1; + break; + } + } + pthread_mutex_unlock(&fdlist.mut); + + if (fd_found) { + return AEE_SUCCESS; + } + + pthread_mutex_lock(&fdlist.mut); + for(i = 0; i < dma_handle_count; i++) { + if(!dhandles[i].used) { + dhandles[i].fd = fd; + dhandles[i].len = len; + dhandles[i].used = 1; + dhandles[i].attr = attr; + break; + } + } + if(i == dma_handle_count) { + if(dma_handle_count >= MAX_DMA_HANDLES) { + FARF(ERROR, "Error: %s: DMA handle list is already full (count %d)", __func__, dma_handle_count); + nErr = AEE_EOUTOFHANDLES; + } else { + dhandles[dma_handle_count].fd = fd; + dhandles[dma_handle_count].len = len; + dhandles[dma_handle_count].used = 1; + dhandles[dma_handle_count].attr = attr; + dma_handle_count++; + } + } + pthread_mutex_unlock(&fdlist.mut); + +bail: + if(nErr) { + FARF(ERROR, "Error 0x%x: %s failed for fd 0x%x, len %d, attr 0x%x", nErr, __func__, fd, len, attr); + } + return nErr; +} + +int remote_register_dma_handle(int fd, uint32_t len) { + return remote_register_dma_handle_attr(fd, len, 0); +} + +static void unregister_dma_handle(int fd, uint32_t *len, uint32_t *attr) { + int i, last_used = 0; + + *len = 0; + *attr = 0; + + pthread_mutex_lock(&fdlist.mut); + for(i = 0; i < dma_handle_count; i++) { + if(dhandles[i].used) { + if(dhandles[i].fd == fd) { + dhandles[i].used = 0; + *len = dhandles[i].len; + *attr = dhandles[i].attr; + if(i == (dma_handle_count - 1)) { + dma_handle_count = last_used + 1; + } + break; + } else { + last_used = i; + } + } + } + pthread_mutex_unlock(&fdlist.mut); +} + +static int fdlist_fd_from_buf(void* buf, int bufLen, int* nova, void** base, int* attr, int* ofd) { + QNode* pn; + int fd = -1; + pthread_mutex_lock(&fdlist.mut); + QLIST_FOR_ALL(&fdlist.ql, pn) { + if(fd != -1) { + break; + } else { + struct mem_to_fd* tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if(STD_BETWEEN(buf, tofd->buf, (unsigned long)tofd->buf + tofd->size)) { + if(STD_BETWEEN((unsigned long)buf + bufLen -1, tofd->buf, (unsigned long)tofd->buf + tofd->size)) { + fd = tofd->fd; + *nova = tofd->nova; + *base = tofd->buf; + *attr = tofd->attr; + } else { + pthread_mutex_unlock(&fdlist.mut); + FARF(ERROR,"Error %x: Mismatch in buffer address(%p) or size(%x) to the registered FD(%x), address(%p) and size(%x)\n", AEE_EBADPARM, buf, bufLen, tofd->fd, tofd->buf, tofd->size); + return AEE_EBADPARM; + } + } + } + } + *ofd = fd; + pthread_mutex_unlock(&fdlist.mut); + return 0; +} + +static int verify_local_handle(remote_handle64 local) { + struct handle_info* hinfo = (struct handle_info*)(uintptr_t)local; + int nErr = AEE_SUCCESS; + + VERIFYC(hinfo, AEE_EMEMPTR); + VERIFYC((hinfo->hlist >= &hlist[0]) && (hinfo->hlist < &hlist[NUM_DOMAINS_EXTEND]), AEE_EMEMPTR); + VERIFYC(QNode_IsQueuedZ(&hinfo->qn), AEE_ENOSUCHHANDLE); +bail: + if (nErr != AEE_SUCCESS) { + FARF(HIGH, "Error %x: verify local handle failed. handle %p\n", nErr, &local); + } + return nErr; +} + +static int get_domain_from_handle(remote_handle64 local, int *domain) { + struct handle_info *hinfo = (struct handle_info*)(uintptr_t)local; + int dom, nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = verify_local_handle(local))); + dom = (int)(hinfo->hlist - &hlist[0]); + VERIFYC((dom >= 0) && (dom < NUM_DOMAINS_EXTEND), AEE_EINVALIDDOMAIN); + *domain = dom; +bail: + if (nErr != AEE_SUCCESS) { + FARF(HIGH, "Error %x: get domain from handle failed. handle %p\n", nErr, &local); + } + return nErr; +} + +static int get_domain_from_name(const char *uri) { + int domain = DEFAULT_DOMAIN_ID; + + if(uri) { + if(std_strstr(uri, ADSP_DOMAIN)) { + domain = ADSP_DOMAIN_ID; + } else if(std_strstr(uri, MDSP_DOMAIN)) { + domain = MDSP_DOMAIN_ID; + } else if(std_strstr(uri, SDSP_DOMAIN)) { + domain = SDSP_DOMAIN_ID; + } else if(std_strstr(uri, CDSP_DOMAIN)) { + domain = CDSP_DOMAIN_ID; + } else { + domain = INVALID_DOMAIN_ID; + FARF(ERROR, "invalid domain uri: %s\n", uri); + } + if (std_strstr(uri, FASTRPC_SESSION_URI)) { + domain = domain | FASTRPC_SESSION_ID1; + } + } + VERIFY_IPRINTF("get_domain_from_name: %d\n", domain); + return domain; +} + +static int alloc_handle(int domain, remote_handle64 remote, struct handle_info **info) { + struct handle_info* hinfo; + int nErr = AEE_SUCCESS; + + VERIFYC(NULL != (hinfo = malloc(sizeof(*hinfo))), AEE_ENOMEMORY); + hinfo->local = (remote_handle64)(uintptr_t)hinfo; + hinfo->remote = remote; + hinfo->hlist = &hlist[domain]; + QNode_CtorZ(&hinfo->qn); + pthread_mutex_lock(&hlist[domain].mut); + QList_PrependNode(&hlist[domain].ql, &hinfo->qn); + pthread_mutex_unlock(&hlist[domain].mut); + *info = hinfo; + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: alloc handle failed. domain %d\n", nErr, domain); + } + return nErr; +} + +#define IS_CONST_HANDLE(h) (((h) < 0xff) ? 1 : 0) +static int is_last_handle(int domain) { + QNode* pn; + int nErr = AEE_SUCCESS, empty = 0; + + pthread_mutex_lock(&hlist[domain].mut); + if(!(hlist[domain].domainsupport && !hlist[domain].nondomainsupport)){ + VERIFY_IPRINTF("Error %x: hlist[domain].domainsupport && !hlist[domain].nondomainsupport\n",AEE_EBADDOMAIN); + goto bail; + } + empty = 1; + if (!QList_IsEmpty(&hlist[domain].ql)) { + empty = 1; + QLIST_FOR_ALL(&hlist[domain].ql, pn) { + struct handle_info* hi = STD_RECOVER_REC(struct handle_info, qn, pn); + empty = empty & IS_CONST_HANDLE(hi->remote); + if(!empty) + break; + } + } +bail: + pthread_mutex_unlock(&hlist[domain].mut); + if (nErr != AEE_SUCCESS) { + VERIFY_IPRINTF("Error %x: is_last_handle %d failed\n", nErr, domain); + } + return empty; +} + +static int free_handle(remote_handle64 local) { + struct handle_info* hinfo = (struct handle_info*)(uintptr_t)local; + int nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = verify_local_handle(local))); + pthread_mutex_lock(&hinfo->hlist->mut); + QNode_DequeueZ(&hinfo->qn); + pthread_mutex_unlock(&hinfo->hlist->mut); + free(hinfo); + hinfo = NULL; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: free handle failed %p\n", nErr, &local); + } + return nErr; +} + +static int get_handle_remote(remote_handle64 local, remote_handle64 *remote) { + struct handle_info* hinfo = (struct handle_info*)(uintptr_t)local; + int nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = verify_local_handle(local))); + *remote = hinfo->remote; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: get handle remote failed %p\n", nErr, &local); + } + return nErr; +} + +void set_thread_context(int domain) { + if(tlsKey != INVALID_KEY) { + pthread_setspecific(tlsKey, (void*)&hlist[domain]); + } +} + +int get_domain_id() { + int domain; + struct handle_list* list; + list = (struct handle_list*)pthread_getspecific(tlsKey); + if(list && hlist){ + domain = (int)(list - &hlist[0]); + }else{ + domain = DEFAULT_DOMAIN_ID; + } + return domain; +} + +int is_smmu_enabled(void) { + struct handle_list* list; + int domain, nErr = 0; + + list = (struct handle_list*)pthread_getspecific(tlsKey); + if (list) { + domain = (int)(list - &hlist[0]); + VERIFY((domain >= 0) && (domain < NUM_DOMAINS_EXTEND)); + return hlist[domain].info & FASTRPC_INFO_SMMU; + } +bail: + return 0; +} + +static int fdlist_fd_to_buf(void *buf) +{ + QNode *pn; + int fd = -1; + pthread_mutex_lock(&fdlist.mut); + QLIST_FOR_ALL(&fdlist.ql, pn) + { + if (fd != -1) + { + break; + } + else + { + struct mem_to_fd *tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if (STD_BETWEEN(buf, tofd->buf, (unsigned long)tofd->buf + tofd->size)) + { + fd = tofd->fd; + } + } + } + pthread_mutex_unlock(&fdlist.mut); + return fd; +} + +int remote_handle_invoke_domain(int domain, remote_handle handle, uint32_t sc, remote_arg* pra) { + struct fastrpc_invoke invoke; + struct fastrpc_invoke_args *args; + int bufs, i, req, nErr = 0; + int dev; + VERIFY(dev != -1); + invoke.handle = handle; + invoke.sc = sc; + struct handle_list* list; + + VERIFYC(-1 != (dev = open_dev(domain)), AEE_EINVALIDDEVICE); + list = &hlist[domain]; + if(0 == pthread_getspecific(tlsKey)) { + pthread_setspecific(tlsKey, (void*)list); + } + bufs = REMOTE_SCALARS_LENGTH(sc); + + args = malloc(bufs * sizeof(*args)); + if (!args) + return -ENOMEM; + + invoke.args = (__u64)(uintptr_t)args; + + for (i = 0; i < bufs; i++) + { + args[i].reserved = 0; + args[i].length = pra[i].buf.nLen; + args[i].ptr = (__u64)(uintptr_t)pra[i].buf.pv; + + + if (pra[i].buf.nLen) + { + FARF(HIGH,"debug:sc:%x,handle:%x,len:%llx\n",sc,pra[i].buf.nLen); + args[i].fd = fdlist_fd_to_buf(pra[i].buf.pv); + } + else + { + args[i].fd = -1; + } + } + req = FASTRPC_IOCTL_INVOKE; + + if (0 == pthread_getspecific(tlsKey)) + { + pthread_setspecific(tlsKey, (void *)1); + } + FARF(HIGH,"debug:sc:%x,handle:%x\n",sc,handle); + nErr = ioctl(dev, req, (unsigned long)&invoke); + free(args); +bail: + return nErr; +} + +int remote_handle_invoke(remote_handle handle, uint32_t sc, remote_arg* pra) { + struct handle_list* list; + int domain = DEFAULT_DOMAIN_ID, nErr = AEE_SUCCESS; + + VERIFYC(handle != (remote_handle)-1, AEE_EBADHANDLE); + list = (struct handle_list*)pthread_getspecific(tlsKey); + + if(list) { + domain = (int)(list - &hlist[0]); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EINVALIDDOMAIN); + } else { + domain = DEFAULT_DOMAIN_ID; + } + VERIFY(AEE_SUCCESS == (nErr = remote_handle_invoke_domain(domain, handle, sc, pra))); +bail: + if (nErr != AEE_SUCCESS) { + FARF(HIGH, "Error %x: remote handle invoke failed. domain %d, handle %x, sc %x, pra %p\n", nErr, domain, handle, sc, pra); + } + return nErr; +} + +int remote_handle64_invoke(remote_handle64 local, uint32_t sc, remote_arg* pra) { + remote_handle64 remote; + int nErr = AEE_SUCCESS, domain = DEFAULT_DOMAIN_ID; + + VERIFYC(local != (remote_handle64)-1, AEE_EBADHANDLE); + VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(local, &domain))); + VERIFY(AEE_SUCCESS == (nErr = get_handle_remote(local, &remote))); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_invoke_domain(domain, remote, sc, pra))); +bail: + if (nErr != AEE_SUCCESS) { + FARF(HIGH, "Error %x: remote handle64 invoke failed. domain %d, handle %p, sc %x, pra %p\n", nErr, domain, &local, sc, pra); + } + return nErr; +} + +int listener_android_geteventfd(int domain, int *fd); +int remote_handle_open_domain(int domain, const char* name, remote_handle *ph) +{ + char dlerrstr[255]; + int dlerr = 0, nErr = AEE_SUCCESS; + if (!std_strncmp(name, ITRANSPORT_PREFIX "geteventfd", std_strlen(ITRANSPORT_PREFIX "geteventfd"))) { + FARF(HIGH, "getting event fd \n"); + return listener_android_geteventfd(domain, (int *)ph); + } + if (!std_strncmp(name, ITRANSPORT_PREFIX "attachguestos", std_strlen(ITRANSPORT_PREFIX "attachguestos"))) { + FARF(HIGH, "setting attach mode to guestos : %d\n", domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + hlist[domain].dsppd = GUEST_OS; + return AEE_SUCCESS; + } + if (!std_strncmp(name, ITRANSPORT_PREFIX "createstaticpd", std_strlen(ITRANSPORT_PREFIX "createstaticpd"))) { + FARF(HIGH, "creating static pd on domain: %d\n", domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + const char *pdName = name + std_strlen(ITRANSPORT_PREFIX "createstaticpd:"); + hlist[domain].dsppdname = (char *)malloc((std_strlen(pdName) + 1)*(sizeof(char))); + VERIFYC(NULL != hlist[domain].dsppdname, AEE_ENOMEMORY); + std_strlcpy(hlist[domain].dsppdname, pdName, std_strlen(pdName) + 1); + if (!std_strncmp(pdName, "audiopd", std_strlen("audiopd"))) { + hlist[domain].dsppd = STATIC_USER_PD; + } else if (!std_strncmp(pdName, "sensorspd", std_strlen("sensorspd"))) { + hlist[domain].dsppd = ATTACH_SENSORS_PD; + } else if (!std_strncmp(pdName, "rootpd", std_strlen("rootpd"))) { + hlist[domain].dsppd = GUEST_OS_SHARED; + } + return AEE_SUCCESS; + } + if (std_strbegins(name, ITRANSPORT_PREFIX "attachuserpd")) { + FARF(HIGH, "setting attach mode to userpd : %d\n", domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + hlist[domain].dsppd = USER_PD; + return AEE_SUCCESS; + } + VERIFYC(-1 != open_dev(domain), AEE_EINVALIDDEVICE); + FARF(HIGH, "Name of the shared object to open %s\n", name); + VERIFY(AEE_SUCCESS == (nErr = remotectl_open(name, (int*)ph, dlerrstr, sizeof(dlerrstr), &dlerr))); + VERIFY(AEE_SUCCESS == (nErr = dlerr)); + +bail: + if(dlerr != 0) { + FARF(ERROR, "Error %x: remote handle open domain failed. domain %d, name %s, dlerror %s\n", nErr, domain, name, dlerrstr); + } + if (nErr != 0) + if (hlist[domain].dsppdname != NULL) + { + free(hlist[domain].dsppdname); + hlist[domain].dsppdname = NULL; + } + return nErr; +} + +int remote_handle_open(const char* name, remote_handle *ph) { + int nErr = 0, domain; + domain = DEFAULT_DOMAIN_ID; + VERIFY(!remote_handle_open_domain(domain, name, ph)); + hlist[domain].nondomainsupport = 1; +bail: + return nErr; +} + +int remote_handle64_open(const char* name, remote_handle64 *ph) +{ + struct handle_info* hinfo = 0; + remote_handle h = 0; + int domain, nErr = 0; + + domain = get_domain_from_name(name); + VERIFYC(domain >= 0, AEE_EINVALIDDOMAIN); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_open_domain(domain, name, &h))); + hlist[domain].domainsupport = 1; + VERIFY(AEE_SUCCESS == (nErr = alloc_handle(domain, h, &hinfo))); + *ph = hinfo->local; +bail: + if(nErr) { + if(h) + remote_handle_close(h); + FARF(HIGH, "Error %x: remote handle64 open failed. name %s\n", nErr, name); + } + return nErr; +} + +int remote_handle_close(remote_handle h) +{ + char dlerrstr[255]; + int dlerr = 0, nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = remotectl_close(h, dlerrstr, sizeof(dlerrstr), &dlerr))); + VERIFY(AEE_SUCCESS == (nErr = dlerr)); +bail: + if (nErr != AEE_SUCCESS) { + FARF(HIGH, "Error %x: remote handle close failed. error %s\n", nErr, dlerrstr); + } + return nErr; +} + +int remote_handle64_close(remote_handle64 handle) { + remote_handle64 remote; + int domain, nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(handle, &domain))); + VERIFY(AEE_SUCCESS == (nErr = get_handle_remote(handle, &remote))); + set_thread_context(domain); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_close((remote_handle)remote))); +bail: + free_handle(handle); + if (is_last_handle(domain)) { + domain_deinit(domain); + } + if (nErr != AEE_SUCCESS) { + FARF(HIGH, "Error %x: remote handle64 close failed.\n", nErr); + } + return nErr; +} + +int manage_pm_qos(int domain, remote_handle64 h, uint32_t enable, uint32_t latency) { + int nErr = AEE_SUCCESS; + struct fastrpc_latency *qos; + int state = 0; + + if (h == -1) { + /* Handle will be -1 in non-domains invocation. Create session if necessary */ + if (!hlist || (hlist && hlist[domain].dev == -1)) + VERIFYC(-1 != open_dev(domain), AEE_EINVALIDDEVICE); + } else { + /* If the multi-domain handle is valid, then verify that session is created already */ + VERIFY(hlist[domain].dev != -1); + } + qos = &hlist[domain].qos; + VERIFY(qos); + if (qos->exit == FASTRPC_LATENCY_EXIT) + goto bail; + pthread_mutex_lock(&qos->mut); + state = qos->state; + qos->latency = latency; + pthread_mutex_unlock(&qos->mut); + + if (!enable && state == FASTRPC_LATENCY_START) { + qos->exit = FASTRPC_LATENCY_EXIT; + pthread_mutex_lock(&qos->wmut); + pthread_cond_signal(&qos->cond); + pthread_mutex_unlock(&qos->wmut); + } + + if (enable && state == FASTRPC_LATENCY_STOP) { + qos->state = FASTRPC_LATENCY_START; + VERIFY(AEE_SUCCESS == (nErr = pthread_create(&qos->thread, 0, fastrpc_latency_thread_handler, (void*)qos))); + } +bail: + return nErr; +} + +int manage_adaptive_qos(int domain, uint32_t enable) { + int nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + /* If adaptive QoS is already enabled/disabled, then just return */ + if ((enable && hlist[domain].qos.adaptive_qos) || (!enable && !hlist[domain].qos.adaptive_qos)) + return nErr; + + if (hlist[domain].dev != -1) { + /* If session is already open on DSP, then make rpc call directly to user PD */ + nErr = remotectl_set_param(FASTRPC_ADAPTIVE_QOS, &enable, 1); + if (nErr) { + FARF(ERROR, "Error: %s: remotectl_set_param failed to reset adaptive QoS on DSP to %d on domain %d", + __func__, enable, domain); + goto bail; + } else { + hlist[domain].qos.adaptive_qos = ((enable == FASTRPC_ADAPTIVE_QOS)? 1:0); + } + } else { + /* If session is not created already, then just process attribute */ + hlist[domain].qos.adaptive_qos = ((enable == FASTRPC_ADAPTIVE_QOS)? 1:0); + } + + if (enable) + FARF(ALWAYS, "%s: Successfully enabled adaptive QoS on domain %d", __func__, domain); + else + FARF(ALWAYS, "%s: Disabled adaptive QoS on domain %d", __func__, domain); +bail: + return nErr; +} + +int remote_handle_control_domain(int domain, remote_handle64 h, uint32_t req, void* data, uint32_t len) { + int nErr = AEE_SUCCESS; + + switch (req) { + case DSPRPC_CONTROL_LATENCY: + { + struct remote_rpc_control_latency *lp = (struct remote_rpc_control_latency*)data; + VERIFYC(lp, AEE_EBADPARM); + VERIFYC(len == sizeof(struct remote_rpc_control_latency), AEE_EBADPARM); + + switch(lp->enable) { + /* Only one of PM QoS or adaptive QoS can be enabled */ + case FASTRPC_DISABLE_QOS: + { + VERIFY(AEE_SUCCESS == (nErr = manage_adaptive_qos(domain, FASTRPC_DISABLE_QOS))); + VERIFY(AEE_SUCCESS == (nErr = manage_pm_qos(domain, h, FASTRPC_DISABLE_QOS, lp->latency))); + break; + } + case FASTRPC_PM_QOS: + { + VERIFY(AEE_SUCCESS == (nErr = manage_adaptive_qos(domain, FASTRPC_DISABLE_QOS))); + VERIFY(AEE_SUCCESS == (nErr = manage_pm_qos(domain, h, FASTRPC_PM_QOS, lp->latency))); + break; + } + case FASTRPC_ADAPTIVE_QOS: + { + /* Disable PM QoS if enabled and then enable adaptive QoS */ + VERIFY(AEE_SUCCESS == (nErr = manage_pm_qos(domain, h, FASTRPC_DISABLE_QOS, lp->latency))); + VERIFY(AEE_SUCCESS == (nErr = manage_adaptive_qos(domain, FASTRPC_ADAPTIVE_QOS))); + break; + } + default: + nErr = AEE_EBADPARM; + FARF(ERROR, "Error: %s: Bad enable parameter %d passed for QoS control", __func__, lp->enable); + break; + } + break; + } + default: + nErr = AEE_EUNSUPPORTEDAPI; + FARF(ERROR, "Error: %s: remote handle control called with unsupported request ID %d", __func__, req); + break; + } +bail: + if (nErr != AEE_SUCCESS) + FARF(ERROR, "Error 0x%x: %s failed for request ID %d on domain %d", nErr, __func__, req, domain); + return nErr; +} + +int remote_handle_control(uint32_t req, void* data, uint32_t len) { + struct handle_list* list; + int domain = DEFAULT_DOMAIN_ID, nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = remote_handle_control_domain(domain, -1, req, data, len))); +bail: + if (nErr != AEE_SUCCESS) + FARF(ERROR, "Error 0x%x: %s failed for request ID %d", nErr, __func__, req); + return nErr; +} + +int remote_handle64_control(remote_handle64 handle, uint32_t req, void* data, uint32_t len) { + int nErr = AEE_SUCCESS, domain = 0; + + VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(handle, &domain))); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_control_domain(domain, handle, req, data, len))); + +bail: + if (nErr != AEE_SUCCESS) + FARF(ERROR, "Error 0x%x: %s failed for request ID %d", nErr, __func__, req); + return nErr; +} + +static int store_domain_thread_params(int domain, struct remote_rpc_thread_params *params, uint32_t req) +{ + int nErr = AEE_SUCCESS; + + if (hlist[domain].dev != -1) { + nErr = AEE_ENOTALLOWED; + FARF(ERROR, "%s: Session already open on domain %d ! Set parameters before making any RPC calls", + __func__, domain); + goto bail; + } + if (params->prio != -1) { + /* Valid QuRT thread priorities are 1 to 255 */ + unsigned int min_prio = 1, max_prio = 255; + + if ((params->prio < min_prio) || (params->prio > max_prio)) { + nErr = AEE_EBADPARM; + FARF(ERROR, "%s: Priority %d is invalid! Should be between %d and %d", + __func__, params->prio, min_prio, max_prio); + goto bail; + } else + hlist[domain].th_params.prio = (uint32_t) params->prio; + } + if (params->stack_size != -1) { + /* Stack size passed by user should be between 16 KB and 8 MB */ + unsigned int min_stack_size = 16*1024, max_stack_size = 8*1024*1024; + + if ((params->stack_size < min_stack_size) || (params->stack_size > max_stack_size)) { + nErr = AEE_EBADPARM; + FARF(ERROR, "%s: Stack size %d is invalid! Should be between %d and %d", + __func__, params->stack_size, min_stack_size, max_stack_size); + goto bail; + } else + hlist[domain].th_params.stack_size = (uint32_t) params->stack_size; + } + hlist[domain].th_params.reqID = req; +bail: + if (nErr != AEE_SUCCESS) + FARF(ERROR, "Error 0x%x: %s failed for domain %d", nErr, __func__, domain); + return nErr; +} + +/* Set remote session parameters like thread stack size, running on unsigned PD etc */ +int remote_session_control(uint32_t req, void *data, uint32_t datalen) +{ + int nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + switch (req) { + case FASTRPC_THREAD_PARAMS: + { + struct remote_rpc_thread_params *params = (struct remote_rpc_thread_params*)data; + if (!params) { + nErr = AEE_EBADPARM; + FARF(ERROR, "%s: Thread params struct passed is %p", __func__, params); + goto bail; + } + VERIFYC(datalen == sizeof(struct remote_rpc_thread_params), AEE_EINVALIDFORMAT); + if (params->domain != -1) { + if ((params->domain < 0) || (params->domain >= NUM_DOMAINS_EXTEND)) { + nErr = AEE_EINVALIDDOMAIN; + FARF(ERROR, "%s: Invalid domain ID %d passed", __func__, params->domain); + goto bail; + } + VERIFY(AEE_SUCCESS == (nErr = store_domain_thread_params(params->domain, params, req))); + } else { + /* If domain is -1, then set parameters for all domains */ + for (int i = 0; i < NUM_DOMAINS_EXTEND; i++) { + VERIFY(AEE_SUCCESS == (nErr = store_domain_thread_params(i, params, req))); + } + } + break; + } + case DSPRPC_CONTROL_UNSIGNED_MODULE: + { + // Handle the unsigned module offload request + struct remote_rpc_control_unsigned_module *um = (struct remote_rpc_control_unsigned_module*)data; + VERIFYC(datalen == sizeof(struct remote_rpc_control_unsigned_module), AEE_EINVALIDFORMAT); + VERIFY(um != NULL); + FARF (HIGH, "%s Unsigned module offload enable %d for domain %d", __func__, um->enable, um->domain); + if (um->domain != -1) { + VERIFYC((um->domain >= 0) && (um->domain < NUM_DOMAINS_EXTEND), AEE_EINVALIDDOMAIN); + hlist[um->domain].unsigned_module = um->enable? 1 :0 ; + } else { + for (int ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + hlist[ii].unsigned_module = um->enable? 1: 0; + } + } + } + break; + default: + nErr = AEE_EUNSUPPORTEDAPI; + FARF(ERROR, "%s: Unsupported request ID %d", __func__, req); + break; + } +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %d", nErr, __func__, req); + } + return nErr; +} + +int remote_mmap64(int fd, uint32_t flags, uint64_t vaddrin, int64_t size, uint64_t* vaddrout) { + struct handle_list* list; + struct fastrpc_ioctl_mmap mmap; + int dev, domain, nErr = AEE_SUCCESS; + + list = (struct handle_list*)pthread_getspecific(tlsKey); + VERIFYC(NULL != list, AEE_EMEMPTR); + domain = (int)(list - &hlist[0]); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EINVALIDDOMAIN); + VERIFYC(-1 != (dev = open_dev(domain)), AEE_EINVALIDDEVICE); + mmap.fd = fd; + mmap.flags = flags; + mmap.vaddrin = vaddrin; + mmap.size = size; + FARF(HIGH, "Entering %s : fd %d, vaddrin %llx, size %llx ioctl %x\n", __func__, fd, vaddrin, size, FASTRPC_IOCTL_MMAP); + VERIFY(AEE_SUCCESS == (nErr = ioctl(dev, FASTRPC_IOCTL_MMAP, (unsigned long)&mmap))); + *vaddrout = mmap.vaddrout; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: remote mmap64 failed. fd %x, flags %x, vaddrin %llx, size %zx\n", nErr, fd, flags, vaddrin, size); + } + return nErr; +} + +int remote_mmap(int fd, uint32_t flags, uint32_t vaddrin, int size, uint32_t* vaddrout) { + return remote_mmap64(fd, flags, (uintptr_t)vaddrin, (int64_t)size, (uint64_t*)vaddrout); +} + +int remote_munmap64(uint64_t vaddrout, int64_t size) { + struct handle_list* list; + struct fastrpc_ioctl_munmap munmap; + int dev, domain, nErr = AEE_SUCCESS; + + list = (struct handle_list*)pthread_getspecific(tlsKey); + VERIFYC(NULL != list, AEE_EMEMPTR); + domain = (int)(list - &hlist[0]); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EINVALIDDOMAIN); + VERIFYC(-1 != (dev = open_dev(domain)), AEE_EINVALIDDEVICE); + VERIFY(list->dev > 0); + munmap.vaddrout = vaddrout; + munmap.size = size; + FARF(HIGH, "Entering %s : vaddrin %llx, size %llx\n", __func__, vaddrout, size); + VERIFY(AEE_SUCCESS == (nErr = ioctl(dev, FASTRPC_IOCTL_MUNMAP, (unsigned long)&munmap))); +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: remote munmap64 failed. vaddrout %p, size %zx\n", nErr, vaddrout, size); + } + return nErr; +} + +int remote_munmap(uint32_t vaddrout, int size) { + return remote_munmap64((uintptr_t)vaddrout, (int64_t)size); +} + +static int remote_unmap_fd(void *buf, int size, int fd, int attr) { + int nErr = 0; + int i; + struct fastrpc_ioctl_munmap map; + + VERIFY(hlist); + map.vaddrout = (uintptr_t) buf; + map.size = size; + for (i = 0; i < NUM_DOMAINS; i++) { + pthread_mutex_lock(&hlist[i].mut); + if (hlist[i].dev != -1) { + nErr = ioctl(hlist[i].dev, FASTRPC_IOCTL_MUNMAP, (unsigned long)&map); + if (nErr) + FARF(LOW, "unmap_fd: device found %d for domain %d returned %d", hlist[i].dev, i, nErr); + } + pthread_mutex_unlock(&hlist[i].mut); + } +bail: + return nErr; +} + + +int remote_set_mode(uint32_t mode) { + int i; + for(i = 0; i < NUM_DOMAINS_EXTEND; i++) { + hlist[i].mode = mode; + hlist[i].setmode = 1; + } + return AEE_SUCCESS; +} + +#ifdef __ANDROID__ +#include <android/log.h> +extern const char* __progname; +void HAP_debug(const char *msg, int level, const char *filename, int line) { + __android_log_print(level, __progname, "%s:%d: %s", filename, line, msg); +} +#else +extern const char* __progname; +void HAP_debug(const char *msg, int level, const char *filename, int line) { + printf("hello %s - %s:%d: %s", __progname, filename, line, msg); +} +#endif + +PL_DEP(fastrpc_apps_user); +PL_DEP(gpls); +PL_DEP(apps_mem); +PL_DEP(apps_std); +PL_DEP(rpcmem); +PL_DEP(listener_android); + +static int attach_guestos(int domain) { + int attach; + + switch(domain & DOMAIN_ID_MASK) { + case MDSP_DOMAIN_ID: + case ADSP_DOMAIN_ID: + attach = USER_PD; + break; + case CDSP_DOMAIN_ID: + attach = USER_PD; + break; + default: + attach = GUEST_OS; + break; + } + return attach; +} + +static void domain_deinit(int domain) { + QNode *pn; + remote_handle64 handle; + + if(!hlist) { + return; + } + + pthread_mutex_lock(&hlist[domain].mut); + FARF(HIGH, "domain_deinit for domain %d: dev %d \n", domain, hlist[domain].dev); + if(hlist[domain].dev != -1) { + handle = get_adsp_current_process1_handle(domain); + if(handle != INVALID_HANDLE) { + adsp_current_process1_exit(handle); + } else { + adsp_current_process_exit(); + } + + listener_android_domain_deinit(domain); + deinitFileWatcher(domain); + fastrpc_perf_deinit(); + fastrpc_latency_deinit(&hlist[domain].qos); + while((pn = QList_Pop(&hlist[domain].ql))) { + struct handle_info* hi = STD_RECOVER_REC(struct handle_info, qn, pn); + free(hi); + hi = NULL; + } + hlist[domain].cphandle = 0; + hlist[domain].msghandle = 0; + hlist[domain].domainsupport = 0; + hlist[domain].nondomainsupport = 0; + hlist[domain].initialized = 0; + hlist[domain].dsppd = attach_guestos(domain); + if (hlist[domain].dsppdname != NULL) + { + free(hlist[domain].dsppdname); + hlist[domain].dsppdname = NULL; + } + + FARF(HIGH, "exit: closing %d, rpc errors are expected.\n", domain); + + if (close(hlist[domain].dev)) + FARF(ERROR, "exit: failed to close file descriptor for domain %d\n", domain); + + hlist[domain].dev = -1; + } + if(hlist[domain].pdmem) { + rpcmem_free_internal(hlist[domain].pdmem); + hlist[domain].pdmem = NULL; + } + pthread_mutex_unlock(&hlist[domain].mut); +} + +#define ALIGN_B(p, a) (((p) + ((a) - 1)) & ~((a) - 1)) + +static const char* get_domain_name(int domain_id) { + const char* name; + int domain = domain_id & DOMAIN_ID_MASK; + + switch (domain) { + case ADSP_DOMAIN_ID: + name = ADSPRPC_DEVICE; + break; + case SDSP_DOMAIN_ID: + name = SDSPRPC_DEVICE; + break; + case MDSP_DOMAIN_ID: + name = MDSPRPC_DEVICE; + break; + case CDSP_DOMAIN_ID: + name = CDSPRPC_DEVICE; + break; + default: + name = DEFAULT_DEVICE; + break; + } + return name; +} + +/* Returns the name of the domain based on the following + ADSP/SLPI/MDSP - Return Secure node + CDSP - Return default node + */ +static const char* get_secure_domain_name(int domain_id) { + const char* name; + int domain = domain_id & DOMAIN_ID_MASK; + + switch (domain) { + case ADSP_DOMAIN_ID: + case SDSP_DOMAIN_ID: + case MDSP_DOMAIN_ID: + name = SECURE_DEVICE; + break; + case CDSP_DOMAIN_ID: + // Intentional fallthrough + default: + name = DEFAULT_DEVICE; + break; + } + return name; +} + +/* Opens device node based on the domain + This function takes care of the backward compatibility to open + approriate device for following configurations of the device nodes + 1. 4 different device nodes + 2. 1 device node (adsprpc-smd) + 3. 2 device nodes (adsprpc-smd, adsprpc-smd-secure) + Algorithm + For ADSP, SDSP, MDSP domains: + Open secure device node fist + if no secure device, open actual device node + if still no device, open default node + if failed to open the secure node due to permission, + open default node + For CDSP domain: + Open actual device node ("cdsprpc-smd") + if no device, open secure / default device node +*/ +static int open_device_node_internal (int domain_id) { + int dev = -1; + int domain = domain_id & DOMAIN_ID_MASK; + + switch (domain) { + case ADSP_DOMAIN_ID: + case SDSP_DOMAIN_ID: + case MDSP_DOMAIN_ID: + dev = open(get_secure_domain_name(domain), O_NONBLOCK); + if((dev < 0) && (errno == ENOENT)) { + FARF(HIGH, "Device node %s open failed for domain %d (errno %s),\n" + "falling back to node %s \n", + get_secure_domain_name(domain), domain, strerror(errno), + get_domain_name(domain)); + dev = open(get_domain_name(domain), O_NONBLOCK); + if((dev < 0) && (errno == ENOENT)) { + FARF(HIGH, "Device node %s open failed for domain %d (errno %s)," + "falling back to node %s \n", + get_domain_name(domain), domain, strerror(errno), + DEFAULT_DEVICE); + dev = open(DEFAULT_DEVICE, O_NONBLOCK); + } + } else if ((dev < 0) && (errno == EACCES)) { + // Open the default device node if unable to open the + // secure device node due to permissions + FARF(HIGH, "Device node %s open failed for domain %d (errno %s)," + "falling back to node %s \n", + get_secure_domain_name(domain), domain, strerror(errno), + DEFAULT_DEVICE); + dev = open(DEFAULT_DEVICE, O_NONBLOCK); + } + break; + case CDSP_DOMAIN_ID: + dev = open(get_domain_name(domain), O_NONBLOCK); + if((dev < 0) && (errno == ENOENT)) { + FARF(HIGH, "Device node %s open failed for domain %d (errno %s)," + "falling back to node %s \n", + get_domain_name(domain), domain, strerror(errno), + get_secure_domain_name(domain)); + dev = open(get_secure_domain_name(domain), O_NONBLOCK); + } + break; + default: + break; + } + + if (dev < 0) + FARF(ERROR, "Error: Device node open failed for domain %d (errno %s)", + domain, strerror(errno)); + + return dev; +} + + +static int get_process_attrs(int domain) { + int nErr = 0; + uint64 len = 0; + int attrs = 0; + + attrs = FASTRPC_PROPERTY_GET_INT32(FASTRPC_PROP_PROCESS, 0); + if (!attrs) { + const char *env = getenv("ADSP_PROCESS_ATTRS"); + attrs = env == 0 ? 0 : (int)atoi(env); + } + fastrpc_trace = FASTRPC_PROPERTY_GET_INT32(FASTRPC_PROP_TRACE, 0); + attrs |= hlist[domain].qos.adaptive_qos ? FASTRPC_MODE_ADAPTIVE_QOS : 0; + attrs |= hlist[domain].unsigned_module ? FASTRPC_MODE_UNSIGNED_MODULE : 0; + return attrs; +} + +static void get_process_testsig(apps_std_FILE *fp, uint64 *ptrlen) { + int nErr = 0; + uint64 len = 0; + char testsig[PROPERTY_VALUE_MAX]; + + if (fp == NULL || ptrlen == NULL) + return; + + if (FASTRPC_PROPERTY_GET_STR(FASTRPC_PROP_TESTSIG, testsig, NULL)) { + FARF(HIGH, "testsig file loading is %s", testsig); + nErr = apps_std_fopen_with_env("ADSP_LIBRARY_PATH", ";", testsig, "r", fp); + if (nErr == AEE_SUCCESS && *fp != -1) + nErr = apps_std_flen(*fp, &len); + } +bail: + if (nErr) + len = 0; + *ptrlen = len; + return; +} + +int is_kernel_alloc_supported(int dev, int domain) { + return 1; +} + +static int open_shell(int domain_id, apps_std_FILE *fh, int unsigned_shell) { + char *absName = NULL; + char *shell_absName = NULL; + char *domain_str = NULL; + uint16 shell_absNameLen = 0, absNameLen = 0;; + int nErr = AEE_SUCCESS; + int domain = domain_id & DOMAIN_ID_MASK; + const char* shell_name = SIGNED_SHELL; + + if (1 == unsigned_shell) { + shell_name = UNSIGNED_SHELL; + } + + if (domain == MDSP_DOMAIN_ID) { + return nErr; + } + VERIFYC(NULL != (domain_str = (char*)malloc(sizeof(domain))), AEE_ENOMEMORY); + snprintf(domain_str, sizeof(domain), "%d",domain); + + + shell_absNameLen = std_strlen(shell_name) + std_strlen(domain_str) + 1; + + VERIFYC(NULL != (shell_absName = (char*)malloc(sizeof(char) * shell_absNameLen)), AEE_ENOMEMORY); + std_strlcpy(shell_absName, shell_name, shell_absNameLen); + + std_strlcat(shell_absName, domain_str, shell_absNameLen); + + absNameLen = std_strlen("/usr/lib/") + shell_absNameLen + 1; + VERIFYC(NULL != (absName = (char*)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); + std_strlcpy(absName, "/usr/lib/",absNameLen); + std_strlcat(absName, shell_absName, absNameLen); + + nErr = apps_std_fopen(absName, "r", fh); + if (nErr) { + absNameLen = std_strlen("/vendor/dsp/") + shell_absNameLen + 1; + VERIFYC(NULL != (absName = (char*)realloc(absName, sizeof(char) * absNameLen)), AEE_ENOMEMORY); + std_strlcpy(absName, "/vendor/dsp/",absNameLen); + std_strlcat(absName, shell_absName, absNameLen); + + nErr = apps_std_fopen(absName, "r", fh); + if (nErr) { + FARF(HIGH, "Searching for %s%d ...", shell_name, domain); + nErr = apps_std_fopen_with_env("ADSP_LIBRARY_PATH", ";", shell_absName, "r", fh); + } + } + FARF(HIGH, "fopen for shell returned %d", nErr); +bail: + if(domain_str){ + free(domain_str); + domain_str = NULL; + } + if(shell_absName){ + free(shell_absName); + shell_absName = NULL; + } + if(absName){ + free(absName); + absName = NULL; + } + if (nErr != AEE_SUCCESS) { + if (domain == SDSP_DOMAIN_ID && fh != NULL) { + nErr = AEE_SUCCESS; + *fh = -1; + } else { + FARF(ERROR, "open_shell failed with err %d domain %d\n", nErr, domain); + } + } + return nErr; +} + +int open_device_node(int domain) { + int nErr=0; + + VERIFY(!fastrpc_init_once()); + + pthread_mutex_lock(&hlist[domain].mut); + if(hlist[domain].dev == -1) { + hlist[domain].dev = open_device_node_internal(domain); + /* the domain was opened but not apps initialized */ + hlist[domain].initialized = 0; + } + pthread_mutex_unlock(&hlist[domain].mut); +bail: + return hlist[domain].dev; +} + +static int apps_dev_init(int domain) { + int nErr = AEE_SUCCESS; + struct fastrpc_init_create uproc = {0}; + apps_std_FILE fh = -1; + int battach; + uint32_t info = domain & DOMAIN_ID_MASK; + + FARF(HIGH, "starting %s for domain %d", __func__, domain); + pthread_mutex_lock(&hlist[domain].mut); + pthread_setspecific(tlsKey, (void*)&hlist[domain]); + battach = hlist[domain].dsppd; + if(!hlist[domain].initialized) { + if (hlist[domain].dev == -1) + hlist[domain].dev = open_device_node_internal(domain); + + VERIFYC(hlist[domain].dev >= 0, AEE_EFOPEN); + FARF(HIGH, "%s: device %d opened with info 0x%x (attach %d)", __func__, hlist[domain].dev, hlist[domain].info, battach); + hlist[domain].initialized = 1; + //keep the memory we used to allocate + if (battach == GUEST_OS || battach == GUEST_OS_SHARED) { + FARF(HIGH, "%s: attaching to guest OS for domain %d", __func__, domain); + VERIFY(!ioctl(hlist[domain].dev, FASTRPC_IOCTL_INIT_ATTACH) || errno == ENOTTY); + } else if (battach == USER_PD) { + uint64 len = 0; + uint64 filelen = 0; + int readlen = 0, eof; + int procattr = 0; + apps_std_FILE fsig = -1; + uint64 siglen = 0; + + VERIFY(0 == open_shell(domain, &fh, hlist[domain].unsigned_module)); + + hlist[domain].procattrs = get_process_attrs(domain); + if (IS_DEBUG_MODE_ENABLED(hlist[domain].procattrs)) + get_process_testsig(&fsig, &siglen); + + if (fh != -1) { + VERIFY(AEE_SUCCESS == (nErr = apps_std_flen(fh, &len))); + filelen = len + siglen; + VERIFYC(filelen < INT_MAX, AEE_EBADSIZE); + pthread_mutex_unlock(&hlist[domain].mut); + FARF(HIGH,"debug:file len:%llx",filelen); + FARF(HIGH,"debug:file len to rpc malloc:%x",filelen); + uproc.file = (__u64)rpcmem_alloc_internal(0, RPCMEM_HEAP_DEFAULT, (int)(filelen)); + pthread_mutex_lock(&hlist[domain].mut); + VERIFYC(uproc.file, AEE_ENORPCMEMORY); + VERIFY(AEE_SUCCESS == (nErr = apps_std_fread(fh, (void *)uproc.file, len, &readlen, &eof))); + VERIFYC((int)len == readlen, AEE_EFREAD); + uproc.filefd = rpcmem_to_fd_internal((void *)uproc.file); + uproc.filelen = (int)len; + VERIFYC(uproc.filefd != -1, AEE_EINVALIDFD); + } else { + FARF(ERROR, "Unable to open shell file\n"); + } + uproc.attrs = hlist[domain].procattrs; + if(siglen && fsig != -1) { + VERIFY(AEE_SUCCESS == (nErr = apps_std_fread(fsig, (byte*)(uproc.file + len), siglen, &readlen, &eof))); + VERIFYC(siglen == (uint64)readlen, AEE_EFREAD); + uproc.siglen = siglen; + uproc.filelen = len + siglen; + } + nErr = ioctl(hlist[domain].dev, FASTRPC_IOCTL_INIT_CREATE, (unsigned long)&uproc); + if (nErr == AEE_SUCCESS) { + FARF(HIGH, "Successfully created user PD on domain %d (attrs 0x%x)", domain, hlist[domain].procattrs); + } + } else { + FARF(ERROR, "Error: %s called for unknown mode %d", __func__, battach); + } + } +bail: + pthread_mutex_unlock(&hlist[domain].mut); + if(uproc.file) { + rpcmem_free_internal((void*)uproc.file); + } + if(fh != -1) { + apps_std_fclose(fh); + } + if(nErr != AEE_SUCCESS) { + domain_deinit(domain); + FARF(ERROR, "Error 0x%x: %s failed for domain %d, errno %s\n", nErr, __func__, domain, strerror(errno)); + } + FARF(HIGH, "Done with %s, err: 0x%x, dev: %d", __func__, nErr, hlist[domain].dev); + return nErr; +} + +__attribute__((destructor)) +static void close_dev(void) { + int i; + for(i = 0; i < NUM_DOMAINS_EXTEND; i++) { + domain_deinit(i); + } + pl_deinit(); + PL_DEINIT(fastrpc_apps_user); +} + +remote_handle64 get_adsp_current_process1_handle(int domain) { + struct handle_info* hinfo; + int nErr = AEE_SUCCESS; + + VERIFYC(hlist[domain].domainsupport, AEE_EBADDOMAIN); + if(hlist[domain].cphandle) { + return hlist[domain].cphandle; + } + VERIFY(AEE_SUCCESS == (nErr = alloc_handle(domain, _const_adsp_current_process1_handle, &hinfo))); + hlist[domain].cphandle = hinfo->local; + return hlist[domain].cphandle; +bail: + if (nErr != AEE_SUCCESS) { + if (hlist[domain].domainsupport) + FARF(ERROR, "Error %x: adsp current process handle failed. domain %d\n", nErr, domain); + else if (!hlist[domain].nondomainsupport) + FARF(ERROR, "Error %x: adsp current process handle failed. domain %d\n", nErr, domain); + } + return INVALID_HANDLE; +} + +remote_handle64 get_adspmsgd_adsp1_handle(int domain) { + struct handle_info* hinfo; + int nErr = AEE_SUCCESS; + + VERIFYC(hlist[domain].domainsupport, AEE_EBADDOMAIN); + if(hlist[domain].msghandle) { + return hlist[domain].msghandle; + } + VERIFY(AEE_SUCCESS == (nErr = alloc_handle(domain, _const_adspmsgd_adsp1_handle, &hinfo))); + hlist[domain].msghandle = hinfo->local; + return hlist[domain].msghandle; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR,"Error %x: get adsp msgd handle failed. domain %d\n", nErr, domain); + } + return INVALID_HANDLE; +} + +static int open_dev(int domain) { + static pthread_once_t pl = PTHREAD_ONCE_INIT; + int init = 0, nErr = AEE_SUCCESS; + + if(hlist && hlist[domain].dev != -1 && hlist[domain].initialized) { + if(0 == pthread_getspecific(tlsKey)) { + pthread_setspecific(tlsKey, (void*)&hlist[domain]); + } + goto bail; + } + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + VERIFY(AEE_SUCCESS == (nErr = pthread_once(&pl, (void*)pl_init))); + init = 1; + pthread_mutex_lock(&hlist[domain].init); + if(hlist && hlist[domain].dev != -1 && hlist[domain].initialized) { + goto bail; + } + VERIFY(AEE_SUCCESS == (nErr = apps_dev_init(domain))); + VERIFY(AEE_SUCCESS == (nErr = listener_android_domain_init(domain))); + initFileWatcher(domain); // Ignore errors + if(hlist){ + fastrpc_perf_init(hlist[domain].dev); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_latency_init(hlist[domain].dev, &hlist[domain].qos))); + } + if (hlist[domain].th_params.prio != DEFAULT_UTHREAD_PRIORITY || hlist[domain].th_params.stack_size != DEFAULT_UTHREAD_STACK_SIZE) { + struct fastrpc_thread_params *uthread_params = &hlist[domain].th_params; + + VERIFY(AEE_SUCCESS == (nErr = pthread_create(&uthread_params->thread, NULL, fastrpc_set_remote_uthread_params, (void*)uthread_params))); + VERIFY(AEE_SUCCESS == (nErr = pthread_join(uthread_params->thread, NULL))); + FARF(ALWAYS, "%s: Successfully set remote user thread priority to %d and stack size to %d", + __func__, uthread_params->prio, uthread_params->stack_size); + } + +bail: + if(init) { + pthread_mutex_unlock(&hlist[domain].init); + } + if(nErr != AEE_SUCCESS) { + domain_deinit(domain); + if(hlist) + FARF(ERROR, "Error %x: open dev %d for domain %d failed\n", nErr, hlist[domain].dev, domain); + return -1; + } + if(hlist){ + FARF(HIGH, "done open dev %d err %d", hlist[domain].dev, nErr); + return hlist[domain].dev; + } else { + return -1; + } +} + +static void fastrpc_apps_user_deinit(void) { + QNode *pn; + int i; + if(tlsKey != INVALID_KEY) { + pthread_key_delete(tlsKey); + tlsKey = INVALID_KEY; + } + PL_DEINIT(apps_mem); + PL_DEINIT(apps_std); + PL_DEINIT(rpcmem); + if(hlist) { + for (i = 0; i < NUM_DOMAINS_EXTEND; i++) { + while((pn = QList_Pop(&hlist[i].ql))) { + struct handle_info* h = STD_RECOVER_REC(struct handle_info, qn, pn); + free(h); + h = NULL; + } + pthread_mutex_destroy(&hlist[i].mut); + pthread_mutex_destroy(&hlist[i].init); + } + free(hlist); + hlist = NULL; + } + pthread_mutex_destroy(&fdlist.mut); + return; +} + +static void exit_thread(void *value) +{ + remote_handle64 handle; + struct handle_list* list = (struct handle_list*)value; + int domain; + + if(!hlist) { + return; + } + domain = (int)(list - &hlist[0]); + if(hlist[domain].dev != -1) { + FARF(HIGH, "exiting thread domain: %d", domain); + if((domain < NUM_DOMAINS_EXTEND) && + (handle = get_adsp_current_process1_handle(domain)) != INVALID_HANDLE) { + (void)adsp_current_process1_thread_exit(handle); + } else if (domain == DEFAULT_DOMAIN_ID) { + (void)adsp_current_process_thread_exit(); + } + } +} + +static int fastrpc_apps_user_init() { + int nErr = AEE_SUCCESS, i; + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&fdlist.mut, 0); + QList_Ctor(&fdlist.ql); + std_memset(dhandles, 0, sizeof(dhandles)); + VERIFYC(NULL != (hlist = calloc(NUM_DOMAINS_EXTEND, sizeof(*hlist))), AEE_ENOMEMORY); + for (i = 0; i < NUM_DOMAINS_EXTEND; i++) { + hlist[i].dev = -1; + hlist[i].domainsupport = 0; + hlist[i].nondomainsupport = 0; + hlist[i].kmem_support = 0; + hlist[i].th_params.prio = DEFAULT_UTHREAD_PRIORITY; + hlist[i].th_params.stack_size = DEFAULT_UTHREAD_STACK_SIZE; + hlist[i].th_params.reqID = 0; + hlist[i].dsppd = attach_guestos(i); + hlist[i].dsppdname = NULL; + pthread_mutex_init(&hlist[i].mut, &attr); + pthread_mutex_init(&hlist[i].init, 0); + QList_Ctor(&hlist[i].ql); + } + pthread_mutexattr_destroy(&attr); + VERIFY(AEE_SUCCESS == (nErr = pthread_key_create(&tlsKey, exit_thread))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(rpcmem))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_mem))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std))); + GenCrc32Tab(POLY32, crc_table); +bail: + if(nErr) { + FARF(ERROR, "Error %x: fastrpc_apps_user_init failed\n", nErr); + fastrpc_apps_user_deinit(); + } + return nErr; +} + +PL_DEFINE(fastrpc_apps_user, fastrpc_apps_user_init, fastrpc_apps_user_deinit); + +static void frpc_init(void) { + PL_INIT(fastrpc_apps_user); +} + +static int fastrpc_init_once(void) { + static pthread_once_t frpc = PTHREAD_ONCE_INIT; + int nErr = AEE_SUCCESS; + VERIFY(AEE_SUCCESS == (nErr = pthread_once(&frpc, (void*)frpc_init))); +bail: + if(nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: fastrpc init once failed\n", nErr); + } + return nErr == AEE_SUCCESS ? _pl_fastrpc_apps_user()->nErr : nErr; +} + +static int rpcmem_init_me(void) { + rpcmem_init(); + return AEE_SUCCESS; +} +PL_DEFINE(rpcmem, rpcmem_init_me, rpcmem_deinit); diff --git a/src/fastrpc_perf.c b/src/fastrpc_perf.c new file mode 100644 index 0000000..415830b --- /dev/null +++ b/src/fastrpc_perf.c @@ -0,0 +1,217 @@ +/* + * 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. + */ + +#define FARF_ERROR 1 + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include "HAP_farf.h" +#include "verify.h" +#include "remote.h" +#include "rpcmem.h" +#include "AEEstd.h" +#include "adsp_perf.h" +#include "fastrpc_perf.h" +#include "fastrpc_internal.h" +#include "fastrpc_apps_user.h" + + +#ifdef ANDROID_P +#define PERF_KEY_KERNEL "vendor.fastrpc.perf.kernel" +#define PERF_KEY_ADSP "vendor.fastrpc.perf.adsp" +#define PERF_KEY_FREQ "vendor.fastrpc.perf.freq" +#else +#define PERF_KEY_KERNEL "fastrpc.perf.kernel" +#define PERF_KEY_ADSP "fastrpc.perf.adsp" +#define PERF_KEY_FREQ "fastrpc.perf.freq" +#endif + +#define PERF_MODE 2 +#define PERF_OFF 0 +#define PERF_KERNEL_MASK (0x1) +#define PERF_ADSP_MASK (0x2) +#define PERF_KEY_STR_MAX (2*1024) +#define PERF_MAX_NUM_KEYS 64 + +#define PERF_NS_TO_US(n) ((n)/1000) + +#define IS_KEY_ENABLED(name) (!std_strncmp((name), "perf_invoke_count", 17) || \ + !std_strncmp((name), "perf_mod_invoke", 15) || \ + !std_strncmp((name), "perf_rsp", 8) || \ + !std_strncmp((name), "perf_hdr_sync_flush", 19) || \ + !std_strncmp((name), "perf_sync_flush", 15) || \ + !std_strncmp((name), "perf_hdr_sync_inv", 17) || \ + !std_strncmp((name), "perf_sync_inv", 13)) \ + +struct perf_keys { + int64 data[PERF_MAX_NUM_KEYS]; + int numKeys; + int maxLen; + int enable; + char *keys; +}; + +struct fastrpc_perf { + int count; + int freq; + int perf_on; + struct perf_keys kernel; + struct perf_keys dsp; +}; +struct fastrpc_perf gperf; + +static int perf_kernel_getkeys(int dev) { + int nErr = 0; +bail: + return nErr; +} + +static void get_perf_kernel(int dev, remote_handle handle, uint32_t sc) { +bail: + return; +} + +static void get_perf_adsp(remote_handle handle, uint32_t sc) { + int nErr = 0; + struct fastrpc_perf *p = &gperf; + struct perf_keys *pdsp = &gperf.dsp; + int ii; + char *token; + + char *keystr = pdsp->keys; + VERIFY(0 == adsp_perf_get_usecs(pdsp->data, PERF_MAX_NUM_KEYS)); + VERIFY(pdsp->maxLen < PERF_KEY_STR_MAX); + VERIFY(pdsp->numKeys < PERF_MAX_NUM_KEYS); + FARF(ALWAYS, "\nFastRPC dsp perf for handle 0x%x sc 0x%x\n", handle, sc); + for(ii = 0; ii < pdsp->numKeys; ii++) { + token = keystr; + keystr += strlen(token) + 1; + VERIFY(token); + if (!pdsp->data[ii]) + continue; + if (!std_strncmp(token, "perf_invoke_count",17)) { + FARF(ALWAYS, "fastrpc.dsp.%-20s : %lld \n", token, pdsp->data[ii]); + } else { + FARF(ALWAYS, "fastrpc.dsp.%-20s : %lld us\n", token, pdsp->data[ii]); + } + } +bail: + return; +} + +void fastrpc_perf_update(int dev, remote_handle handle, uint32_t sc) { + int nErr = 0; + struct fastrpc_perf *p = &gperf; + + if (!(p->perf_on && !IS_STATIC_HANDLE(handle) && p->freq > 0)) + return; + + p->count++; + if (p->count % p->freq != 0) + return; + + if (p->kernel.enable) + get_perf_kernel(dev, handle, sc); + + if (p->dsp.enable) + get_perf_adsp(handle, sc); +bail: + return; +} + +static int perf_dsp_enable(void) { + int nErr = 0; + int numKeys = 0, maxLen = 0; + char *keys = NULL; + int ii; + + keys = (char *)rpcmem_alloc_internal(0, RPCMEM_HEAP_DEFAULT, PERF_KEY_STR_MAX); + VERIFY(gperf.dsp.keys = keys); + std_memset(keys, 0, PERF_KEY_STR_MAX); + + VERIFY(0 == adsp_perf_get_keys(keys, PERF_KEY_STR_MAX, &maxLen, &numKeys)); + VERIFY(maxLen < PERF_KEY_STR_MAX); + gperf.dsp.maxLen = maxLen; + gperf.dsp.numKeys = numKeys; + for(ii = 0; ii < numKeys; ii++) { + char *name = keys; + keys += strlen(name) + 1; + if (IS_KEY_ENABLED(name)) + VERIFY(0 == adsp_perf_enable(ii)); + } + FARF(HIGH, "keys enable done maxLen %d numKeys %d", maxLen, numKeys); +bail: + return nErr; +} + +int fastrpc_perf_init(int dev) { + int nErr = 0; + struct fastrpc_perf *p = &gperf; + struct perf_keys *pk = &gperf.kernel; + struct perf_keys *pd = &gperf.dsp; + + pk->enable = FASTRPC_PROPERTY_GET_INT32(PERF_KEY_KERNEL, 0); + pd->enable = FASTRPC_PROPERTY_GET_INT32(PERF_KEY_ADSP, 0); + p->perf_on = (pk->enable || pd->enable) ? PERF_MODE : PERF_OFF; + p->freq = FASTRPC_PROPERTY_GET_INT32(PERF_KEY_FREQ, 1000); + VERIFY(p->freq > 0); + + p->count = 0; + if (pk->enable) { + //VERIFY(!ioctl(dev, FASTRPC_IOCTL_SETMODE, PERF_MODE)); + VERIFY(NULL != (pk->keys = (char *)calloc(sizeof(char), PERF_KEY_STR_MAX))); + VERIFY(0 == perf_kernel_getkeys(dev)); + } + + if (pd->enable) + perf_dsp_enable(); +bail: + if (nErr) { + FARF(HIGH, "fastrpc perf init failed"); + p->perf_on = 0; + } + return nErr; +} + +void fastrpc_perf_deinit(void) { + struct fastrpc_perf *p = &gperf; + if (p->kernel.keys){ + free(p->kernel.keys); + p->kernel.keys = NULL; + } + if (p->dsp.keys){ + rpcmem_free_internal(p->dsp.keys); + p->dsp.keys = NULL; + } + return; +} + diff --git a/src/gpls.c b/src/gpls.c new file mode 100644 index 0000000..4e94b13 --- /dev/null +++ b/src/gpls.c @@ -0,0 +1,72 @@ +/* + * 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 "HAP_farf.h" +#include "pls.h" +#include "HAP_pls.h" +#include "adsp_pls.h" +#include "platform_libs.h" +#include "version.h" + +static struct pls_table gpls; +const char pls_version[] = VERSION_STRING ; +int gpls_init(void) { + pls_ctor(&gpls, 1); + return 0; +} + +void gpls_deinit(void) { + pls_thread_deinit(&gpls); +} + +int HAP_pls_add(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo) { + return pls_add(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int HAP_pls_add_lookup(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo) { + return pls_add_lookup_singleton(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int HAP_pls_lookup(uintptr_t type, uintptr_t key, void** ppo) { + return pls_lookup(&gpls, type, key, ppo); +} + +int adsp_pls_add(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo) { + return pls_add(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int adsp_pls_add_lookup(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo) { + return pls_add_lookup_singleton(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int adsp_pls_lookup(uintptr_t type, uintptr_t key, void** ppo) { + return pls_lookup(&gpls, type, key, ppo); +} + + +PL_DEFINE(gpls, gpls_init, gpls_deinit) diff --git a/src/listener_android.c b/src/listener_android.c new file mode 100644 index 0000000..00729f4 --- /dev/null +++ b/src/listener_android.c @@ -0,0 +1,474 @@ +/* + * 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) diff --git a/src/log_config.c b/src/log_config.c new file mode 100644 index 0000000..b2ef10e --- /dev/null +++ b/src/log_config.c @@ -0,0 +1,543 @@ +/* + * 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. + */ + +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_PRINT_ERROR +#endif // VERIFY_PRINT_ERROR +#include <pthread.h> +#include <unistd.h> +#include <sys/inotify.h> +#include <sys/eventfd.h> +#include <poll.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <limits.h> + +#include "apps_std.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "verify.h" +#include "remote_priv.h" +#include "adsp_current_process.h" +#include "adsp_current_process1.h" +#include "adspmsgd_adsp.h" +#include "adspmsgd_adsp1.h" +#include "rpcmem.h" + +#define EVENT_SIZE ( sizeof (struct inotify_event) ) +#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) +#ifndef AEE_EUNSUPPORTED +#define AEE_EUNSUPPORTED 20 // API is not supported 50 +#endif +#define DEFAULT_ADSPMSGD_MEMORY_SIZE 8192 +#define INVALID_HANDLE (remote_handle64)(-1) +#define ERRNO (errno == 0 ? -1 : errno) + +struct log_config_watcher_params { + int fd; + int event_fd; // Duplicate fd to quit the poll + _cstring1_t* paths; + int* wd; + uint32 numPaths; + pthread_attr_t attr; + pthread_t thread; + unsigned char stopThread; + int asidToWatch; + char* fileToWatch; + char* asidFileToWatch; + char* pidFileToWatch; + boolean adspmsgdEnabled; +}; + +static struct log_config_watcher_params log_config_watcher[NUM_DOMAINS_EXTEND]; +extern const char* __progname; + +const char* get_domain_str(int domain); +remote_handle64 get_adsp_current_process1_handle(int domain); +remote_handle64 get_adspmsgd_adsp1_handle(int domain); + +static int parseLogConfig(int dom, unsigned short mask, char* filenames){ + _cstring1_t* filesToLog = NULL; + int filesToLogLen = 0; + char* tempFiles = NULL; + int nErr = AEE_SUCCESS; + char *saveptr = NULL; + char* path = NULL; + char delim[] = {','}; + int maxPathLen = 0; + int i = 0; + remote_handle64 handle; + + VERIFYC(filenames != NULL, AEE_EINVALIDFILENAME); + + VERIFYC(NULL!= (tempFiles = malloc(sizeof(char) * (std_strlen(filenames) + 1))), AEE_ENOMEMORY); + std_strlcpy(tempFiles,filenames,std_strlen(filenames) + 1); + + // Get the number of folders and max size needed + path = strtok_r (tempFiles, delim, &saveptr); + while (path != NULL){ + maxPathLen = STD_MAX(maxPathLen, std_strlen(path)) + 1; + filesToLogLen++; + path = strtok_r (NULL, delim, &saveptr); + } + + VERIFY_IPRINTF("%s: #files: %d max_len: %d\n", log_config_watcher[dom].fileToWatch, filesToLogLen, maxPathLen); + + // Allocate memory + VERIFYC(NULL != (filesToLog = malloc(sizeof(_cstring1_t)*filesToLogLen)), AEE_ENOMEMORY); + for (i = 0; i < filesToLogLen; ++i){ + VERIFYC(NULL != (filesToLog[i].data = malloc(sizeof(char) * maxPathLen)), AEE_ENOMEMORY); + filesToLog[i].dataLen = maxPathLen; + } + + // Get the number of folders and max size needed + std_strlcpy(tempFiles,filenames,std_strlen(filenames) + 1); + i = 0; + path = strtok_r (tempFiles, delim, &saveptr); + while (path != NULL){ + VERIFYC((filesToLog != NULL) && (filesToLog[i].data != NULL) && + filesToLog[i].dataLen >= (int)strlen(path), AEE_EBADSIZE); + std_strlcpy(filesToLog[i].data, path, filesToLog[i].dataLen); + VERIFY_IPRINTF("%s: %s\n", log_config_watcher[dom].fileToWatch, filesToLog[i].data); + path = strtok_r (NULL, delim, &saveptr); + i++; + } + + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_set_logging_params(handle, mask,filesToLog,filesToLogLen))); + } else { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_set_logging_params(mask,filesToLog,filesToLogLen))); + } + +bail: + if (filesToLog){ + for (i = 0; i < filesToLogLen; ++i){ + if (filesToLog[i].data != NULL){ + free (filesToLog[i].data); + filesToLog[i].data = NULL; + } + } + free(filesToLog); + filesToLog = NULL; + } + + if(tempFiles){ + free(tempFiles); + tempFiles = NULL; + } + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: parse log config failed. domain %d, mask %x, filename %s\n", nErr, dom, mask, filenames); + } + return nErr; +} +// Read log config given the filename +static int readLogConfigFromPath(int dom, const char* base, const char* file){ + int nErr = 0; + apps_std_FILE fp = -1; + uint64 len; + byte* buf = NULL; + int readlen = 0, eof; + unsigned short mask = 0; + char* path = NULL; + char* filenames = NULL; + boolean fileExists = FALSE; + int buf_addr = 0; + remote_handle64 handle; + + len = std_snprintf(0, 0, "%s/%s", base, file) + 1; + VERIFYC(NULL != (path = malloc(sizeof(char) * len)), AEE_ENOMEMORY); + std_snprintf(path, (int)len, "%s/%s", base, file); + VERIFY(AEE_SUCCESS == (nErr = apps_std_fileExists(path,&fileExists))); + if (fileExists == FALSE){ + VERIFY_IPRINTF("%s: Couldn't find file: %s\n",log_config_watcher[dom].fileToWatch, path); + nErr = AEE_ENOSUCHFILE; + goto bail; + } + if (log_config_watcher[dom].adspmsgdEnabled == FALSE){ + handle = get_adspmsgd_adsp1_handle(dom); + if(handle != INVALID_HANDLE) { + adspmsgd_adsp1_init2(handle); + } else if(AEE_EUNSUPPORTED == (nErr = adspmsgd_adsp_init2())) { + nErr = adspmsgd_adsp_init(0, RPCMEM_HEAP_DEFAULT, 0, DEFAULT_ADSPMSGD_MEMORY_SIZE, &buf_addr); + } + if (nErr != AEE_SUCCESS){ + VERIFY_EPRINTF("adspmsgd not supported. nErr=%x\n", nErr); + }else{ + log_config_watcher[dom].adspmsgdEnabled = TRUE; + } + VERIFY_EPRINTF("Found %s. adspmsgd enabled \n", log_config_watcher[dom].fileToWatch); + } + + VERIFY(AEE_SUCCESS == (nErr = apps_std_fopen(path, "r", &fp))); + VERIFY(AEE_SUCCESS == (nErr = apps_std_flen(fp, &len))); + + VERIFYC(len < 511, AEE_EBADSIZE); + VERIFYC(NULL != (buf = calloc(1, sizeof(byte) * (len + 1))), AEE_ENOMEMORY); // extra 1 byte for null character + VERIFYC(NULL != (filenames = malloc(sizeof(byte) * len)), AEE_ENOMEMORY); + VERIFY(AEE_SUCCESS == (nErr = apps_std_fread(fp, buf, len, &readlen, &eof))); + VERIFYC((int)len == readlen, AEE_EFREAD); + + VERIFY_IPRINTF("%s: Config file %s contents: %s\n", log_config_watcher[dom].fileToWatch, path, buf); + + len = sscanf((const char*)buf, "0x%hx %511s", &mask, filenames); + switch (len){ + case 1: + VERIFY_IPRINTF("%s: Setting log mask:0x%x", log_config_watcher[dom].fileToWatch, mask); + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_set_logging_params(handle,mask,NULL,0))); + } else { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_set_logging_params(mask,NULL,0))); + } + break; + case 2: + VERIFY(AEE_SUCCESS == (nErr = parseLogConfig(dom, mask,filenames))); + VERIFY_IPRINTF("%s: Setting log mask:0x%x, filename:%s", log_config_watcher[dom].fileToWatch, mask, filenames); + break; + default: + VERIFY_EPRINTF("%s: No valid data found in config file %s", log_config_watcher[dom].fileToWatch, path); + nErr = AEE_EUNSUPPORTED; + goto bail; + } + +bail: + if (buf != NULL){ + free(buf); + buf = NULL; + } + + if (filenames != NULL){ + free(filenames); + filenames = NULL; + } + + if (fp != -1){ + apps_std_fclose(fp); + } + + if (path != NULL){ + free(path); + path = NULL; + } + + if(nErr != AEE_SUCCESS) { + VERIFY_IPRINTF("Error %x: fopen failed for %s/%s. (%s)\n", nErr, base, file, strerror(ERRNO)); + } + return nErr; +} + + +// Read log config given the watch descriptor +static int readLogConfigFromEvent(int dom, struct inotify_event *event){ + int i = 0; + + // Ensure we are looking at the right file + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){ + if (log_config_watcher[dom].wd[i] == event->wd ){ + if(std_strcmp(log_config_watcher[dom].fileToWatch, event->name) == 0){ + return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].fileToWatch); + }else if (std_strcmp(log_config_watcher[dom].asidFileToWatch, event->name) == 0) { + return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].asidFileToWatch); + }else if (std_strcmp(log_config_watcher[dom].pidFileToWatch, event->name) == 0){ + return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].pidFileToWatch); + } + } + } + VERIFY_IPRINTF("%s: Watch descriptor %d not valid for current process", log_config_watcher[dom].fileToWatch, event->wd); + return AEE_SUCCESS; +} + + +// Read log config given the watch descriptor +static int resetLogConfigFromEvent(int dom, struct inotify_event *event) { + int i = 0; + remote_handle64 handle; + + // Ensure we are looking at the right file + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){ + if (log_config_watcher[dom].wd[i] == event->wd ){ + if( (std_strcmp(log_config_watcher[dom].fileToWatch, event->name) == 0)|| + (std_strcmp(log_config_watcher[dom].asidFileToWatch, event->name) == 0) || + (std_strcmp(log_config_watcher[dom].pidFileToWatch, event->name) == 0) ) { + if (log_config_watcher[dom].adspmsgdEnabled == TRUE){ + handle = get_adspmsgd_adsp1_handle(dom); + if(handle != INVALID_HANDLE) { + adspmsgd_adsp1_deinit(handle); + } else { + adspmsgd_adsp_deinit(); + } + } + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + return adsp_current_process1_set_logging_params(handle,0,NULL,0); + } else { + return adsp_current_process_set_logging_params(0,NULL,0); + } + } + } + } + VERIFY_IPRINTF("%s: Watch descriptor %d not valid for current process", log_config_watcher[dom].fileToWatch, event->wd); + return AEE_SUCCESS; +} + + +static void* file_watcher_thread(void *arg) { + int dom = (int)(uintptr_t)arg; + int ret = 0; + int length = 0; + int nErr = AEE_SUCCESS; + int i = 0; + char buffer[EVENT_BUF_LEN]; + struct pollfd pfd[] = { + {log_config_watcher[dom].fd, POLLIN, 0}, + {log_config_watcher[dom].event_fd, POLLIN, 0} + }; + const char* fileExtension = ".farf"; + int len = 0; + remote_handle64 handle; + + // Check for the presence of the <process_name>.farf file at bootup + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){ + if (0 == readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].fileToWatch)){ + VERIFY_IPRINTF("%s: Log config File %s found.\n", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].paths[i].data ); + } + } + + while(log_config_watcher[dom].stopThread == 0){ + // Block forever + ret = poll(pfd, 2, -1); + if(ret < 0){ + VERIFY_EPRINTF("%s: Error polling for file change. Runtime FARF will not work for this process. errno=%x !", log_config_watcher[dom].fileToWatch, errno); + break; + } else if (pfd[1].revents & POLLIN) { // Check for exit + VERIFY_IPRINTF("Received exit.\n"); + break; + } else { + length = read( log_config_watcher[dom].fd, buffer, EVENT_BUF_LEN ); + i = 0; + while ( i < length ) { + struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ]; + if ( event->len ) { + // Get the asiD for the current process + // Do it once only + if (log_config_watcher[dom].asidToWatch == -1){ + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_getASID(handle,(unsigned int*)&log_config_watcher[dom].asidToWatch ))); + } else { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_getASID((unsigned int*)&log_config_watcher[dom].asidToWatch ))); + } + len = strlen(fileExtension) + strlen(__TOSTR__(INT_MAX)); + VERIFYC(NULL != (log_config_watcher[dom].asidFileToWatch = malloc(sizeof(char) * len)), AEE_ENOMEMORY); + snprintf(log_config_watcher[dom].asidFileToWatch, len, "%d%s", log_config_watcher[dom].asidToWatch, fileExtension); + VERIFY_IPRINTF("%s: Watching ASID file %s\n", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].asidFileToWatch); + } + + VERIFY_IPRINTF("%s: %s %d.\n", log_config_watcher[dom].fileToWatch, event->name, event->mask ); + if ( (event->mask & IN_CREATE) || (event->mask & IN_MODIFY)) { + VERIFY_IPRINTF("%s: File %s created.\n", log_config_watcher[dom].fileToWatch, event->name ); + if (0 != readLogConfigFromEvent(dom, event)){ + VERIFY_EPRINTF("%s: Error reading config file %s", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].paths[i].data); + } + } + else if ( event->mask & IN_DELETE ) { + VERIFY_IPRINTF("%s: File %s deleted.\n", log_config_watcher[dom].fileToWatch, event->name ); + if (0 != resetLogConfigFromEvent(dom, event)){ + VERIFY_EPRINTF("%s: Error resetting FARF runtime log config" ,log_config_watcher[dom].fileToWatch); + } + } + } + + i += EVENT_SIZE + event->len; + } + } + } +bail: + if (nErr != AEE_SUCCESS){ + VERIFY_EPRINTF("Error %x: file watcher thread exited. Runtime FARF will not work for this process. filename %s\n", nErr, log_config_watcher[dom].fileToWatch); + } + return NULL; +} + +void deinitFileWatcher(int dom) { + int i = 0; + uint64 stop = 10; + remote_handle64 handle; + + log_config_watcher[dom].stopThread = 1; + if (0 < log_config_watcher[dom].event_fd) { + if (write(log_config_watcher[dom].event_fd, &stop, sizeof(uint64)) != sizeof(uint64)) { + VERIFY_EPRINTF("Error: write failed: Cannot set exit flag to watcher thread.\n"); + } + } + if (log_config_watcher[dom].thread) { + pthread_join(log_config_watcher[dom].thread, NULL); + log_config_watcher[dom].thread = 0; + } + if (log_config_watcher[dom].fileToWatch){ + free (log_config_watcher[dom].fileToWatch); + log_config_watcher[dom].fileToWatch = 0; + } + if (log_config_watcher[dom].asidFileToWatch){ + free (log_config_watcher[dom].asidFileToWatch); + log_config_watcher[dom].asidFileToWatch = 0; + } + if (log_config_watcher[dom].pidFileToWatch){ + free (log_config_watcher[dom].pidFileToWatch); + log_config_watcher[dom].pidFileToWatch = 0; + } + if (log_config_watcher[dom].wd){ + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){ + if (log_config_watcher[dom].wd[i] != 0){ + inotify_rm_watch( log_config_watcher[dom].fd, log_config_watcher[dom].wd[i] ); + } + } + free(log_config_watcher[dom].wd); + log_config_watcher[dom].wd = NULL; + } + if (log_config_watcher[dom].paths){ + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){ + if (log_config_watcher[dom].paths[i].data){ + free(log_config_watcher[dom].paths[i].data); + log_config_watcher[dom].paths[i].data = NULL; + } + } + free(log_config_watcher[dom].paths); + log_config_watcher[dom].paths = NULL; + } + if(log_config_watcher[dom].fd != 0){ + close(log_config_watcher[dom].fd); + log_config_watcher[dom].fd = 0; + } + if (log_config_watcher[dom].adspmsgdEnabled == TRUE){ + handle = get_adspmsgd_adsp1_handle(dom); + if (handle != INVALID_HANDLE) { + adspmsgd_adsp1_deinit(handle); + } else { + adspmsgd_adsp_deinit(); + } + log_config_watcher[dom].adspmsgdEnabled = FALSE; + } + + if(log_config_watcher[dom].event_fd != 0){ + close(log_config_watcher[dom].event_fd); + log_config_watcher[dom].event_fd = 0; + } + + log_config_watcher[dom].numPaths = 0; +} + +int initFileWatcher(int dom) { + int nErr = AEE_SUCCESS; + const char* fileExtension = ".farf"; + uint32 len = 0; + uint16 maxPathLen = 0; + int i = 0; + char* name = NULL; + + memset(&log_config_watcher[dom], 0, sizeof(struct log_config_watcher_params)); + log_config_watcher[dom].asidToWatch = 0; + + VERIFYC(NULL != (name = std_basename(__progname)), AEE_EINVALIDPROCNAME); + + len = strlen(name) + strlen(fileExtension) + 1; + VERIFYC(NULL != (log_config_watcher[dom].fileToWatch = malloc(sizeof(char) * len)), AEE_ENOMEMORY); + snprintf(log_config_watcher[dom].fileToWatch, len, "%s%s", name, fileExtension); + + len = strlen(fileExtension) + strlen(__TOSTR__(INT_MAX)); + VERIFYC(NULL != (log_config_watcher[dom].pidFileToWatch = malloc(sizeof(char) * len)), AEE_ENOMEMORY); + snprintf(log_config_watcher[dom].pidFileToWatch, len, "%d%s", getpid(), fileExtension); + + VERIFY_IPRINTF("%s: Watching PID file: %s\n", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].pidFileToWatch); + + log_config_watcher[dom].fd = inotify_init(); + if (log_config_watcher[dom].fd < 0){ + nErr = AEE_EINVALIDFD; + VERIFY_EPRINTF("Error %x: inotify_init failed. errno = %s\n", nErr, strerror(errno)); + goto bail; + } + + // Duplicate the fd, so we can use it to quit polling + log_config_watcher[dom].event_fd = eventfd(0, 0); + if (log_config_watcher[dom].event_fd < 0){ + nErr = AEE_EINVALIDFD; + VERIFY_EPRINTF("Error %x: eventfd in dup failed. errno %s\n", nErr, strerror(errno)); + goto bail; + } + VERIFY_IPRINTF("fd = %d dupfd=%d\n", log_config_watcher[dom].fd, log_config_watcher[dom].event_fd); + + // Get the required size + apps_std_get_search_paths_with_env("ADSP_LIBRARY_PATH", ";", NULL, 0, + &log_config_watcher[dom].numPaths, &maxPathLen); + + maxPathLen += + 1; + + // Allocate memory + VERIFYC(NULL != (log_config_watcher[dom].paths + = malloc(sizeof(_cstring1_t) * log_config_watcher[dom].numPaths)), AEE_ENOMEMORY); + VERIFYC(NULL != (log_config_watcher[dom].wd + = malloc(sizeof(int) * log_config_watcher[dom].numPaths)), AEE_ENOMEMORY); + + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){ + VERIFYC( NULL != (log_config_watcher[dom].paths[i].data + = malloc(sizeof(char) * maxPathLen)), AEE_ENOMEMORY); + log_config_watcher[dom].paths[i].dataLen = maxPathLen; + } + + // Get the paths + VERIFY(AEE_SUCCESS == (nErr = apps_std_get_search_paths_with_env("ADSP_LIBRARY_PATH", ";", + log_config_watcher[dom].paths, log_config_watcher[dom].numPaths, &len, &maxPathLen))); + + maxPathLen += 1; + + VERIFY_IPRINTF("%s: Watching folders:\n", log_config_watcher[dom].fileToWatch); + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){ + // Watch for creation, deletion and modification of files in path + VERIFY_IPRINTF("log file watcher: %s: %s\n",log_config_watcher[dom].fileToWatch, log_config_watcher[dom].paths[i].data); + if((log_config_watcher[dom].wd[i] = inotify_add_watch (log_config_watcher[dom].fd, + log_config_watcher[dom].paths[i].data, IN_CREATE | IN_DELETE)) < 0) { + VERIFY_EPRINTF("Unable to add watcher for folder %s : errno is %s\n", log_config_watcher[dom].paths[i].data, strerror(ERRNO)); + } + } + + // Create a thread to watch for file changes + log_config_watcher[dom].asidToWatch = -1; + log_config_watcher[dom].stopThread = 0; + pthread_create(&log_config_watcher[dom].thread, NULL, file_watcher_thread, (void*)(uintptr_t)dom); +bail: + if (nErr!=AEE_SUCCESS){ + VERIFY_EPRINTF("Error %x: Failed to register with inotify file %s. Runtime FARF will not work for the process %s!", nErr, log_config_watcher[dom].fileToWatch, name); + deinitFileWatcher(dom); + } + + return nErr; +} diff --git a/src/mod_table.c b/src/mod_table.c new file mode 100644 index 0000000..7c92d84 --- /dev/null +++ b/src/mod_table.c @@ -0,0 +1,865 @@ +/* + * 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. + */ +#ifndef FARF_ERROR +#define FARF_ERROR 1 +#endif + +#include <assert.h> +#include "verify.h" +#include "HAP_farf.h" +#include "HAP_pls.h" +#include "mutex.h" +#include "mod_table.h" +#include "platform_libs.h" +#include "remote64.h" +#include "uthash.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "sbuf_parser.h" + +#include <dlfcn.h> + +#define DLOPEN dlopen +#define DLCLOSE dlclose +#define DLSYM dlsym +#define DLERROR dlerror + +/** + * structure for the mod table + * + * you need to define a rw_mutex type and its read/write lock/unlock api's + * which are under the RW_MUTEX namespace. + * + * this library defines 2 functions for opening modules, open_static and + * open_dynamic. Both return a handle that should be closed via close. + * + * you can also register a const handle, an invoke function for a known handle + * value. since handle keys are allocated, you should pick handle values that are + * not going to be returned by malloc (0, or odd). + */ +struct static_mod_table { + RW_MUTEX_T mut; + struct static_mod* staticModOverrides; + struct static_mod* staticMods; + struct const_mod* constMods; + boolean bInit; +}; + +struct open_mod_table { + RW_MUTEX_T mut; + struct open_mod* openMods; + struct static_mod_table* smt; +}; + +typedef int (*invoke_fn)(uint32, remote_arg*); +typedef int (*handle_invoke_fn)(remote_handle64, uint32, remote_arg*); +struct static_mod { + invoke_fn invoke; + handle_invoke_fn handle_invoke; + UT_hash_handle hh; + char uri[1]; +}; + +struct const_mod { + invoke_fn invoke; + handle_invoke_fn handle_invoke; + uint32 key; + remote_handle64 h64; + UT_hash_handle hh; + char uri[1]; +}; + +struct parsed_uri { + const char *file; + int filelen; + const char *sym; + int symlen; + const char *ver; + int verlen; +}; + +struct open_mod { + void* dlhandle; + invoke_fn invoke; + handle_invoke_fn handle_invoke; + uint64 key; + UT_hash_handle hh; + remote_handle64 h64; + int refs; + struct parsed_uri vals; + char uri[1]; +}; + +static int static_mod_table_ctor(struct static_mod_table* me) { + if(me->bInit == 0) { + RW_MUTEX_CTOR(me->mut); + me->staticMods = 0; + me->staticModOverrides = 0; + me->bInit = 1; + } + return 0; +} + +static void static_mod_table_dtor_imp(struct static_mod_table* me) { + struct static_mod *sm, *stmp; + struct const_mod *dm, *ftmp; + if(me->bInit != 0) { + if( me->staticMods || me->constMods || me->staticModOverrides) { + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ITER(hh, me->staticMods, sm, stmp) { + if(me->staticMods) { + HASH_DEL(me->staticMods,sm); + } + free(sm); + sm = NULL; + } + HASH_ITER(hh, me->staticModOverrides, sm, stmp) { + if(me->staticModOverrides) { + HASH_DEL(me->staticModOverrides,sm); + } + free(sm); + sm = NULL; + } + HASH_ITER(hh, me->constMods, dm, ftmp) { + if(me->constMods) { + HASH_DEL(me->constMods,dm); + } + free(dm); + dm = NULL; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + } + RW_MUTEX_DTOR(me->mut); + me->staticMods = 0; + me->staticModOverrides = 0; + me->bInit = 0; + } +} + +static int open_mod_table_ctor_imp(void* ctx, void* data) { + struct open_mod_table* me = (struct open_mod_table*)data; + RW_MUTEX_CTOR(me->mut); + me->openMods = 0; + me->smt = (struct static_mod_table*) ctx; + return 0; +} + +static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h); + +static void open_mod_table_dtor_imp(void* data) { + struct open_mod_table* me = (struct open_mod_table*)data; + struct open_mod *dm, *ftmp; + if( me->openMods) { + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ITER(hh, me->openMods, dm, ftmp) { + if(me->openMods) { + HASH_DEL(me->openMods,dm); + } + if(dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + free(dm); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + } + RW_MUTEX_DTOR(me->mut); + me->openMods = 0; +} +static int open_mod_table_open_from_static(struct open_mod_table* me, + struct static_mod** tbl, + const char* uri, + remote_handle* handle); + +static int open_mod_table_open_static_override(struct open_mod_table* me, const char* uri, remote_handle* handle) { + FARF(HIGH, "open_mod_table_open_static_override"); + return open_mod_table_open_from_static(me, &me->smt->staticModOverrides, uri, handle); +} + + +static int open_mod_table_open_static(struct open_mod_table* me, const char* uri, remote_handle* handle) { + FARF(HIGH, "open_mod_table_open_static"); + return open_mod_table_open_from_static(me, &me->smt->staticMods, uri, handle); +} + +static int static_mod_add(struct static_mod_table* me, struct static_mod** tbl, const char* uri, + int(*invoke)(uint32 sc, remote_arg* pra), + int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra)) { + int nErr = AEE_SUCCESS; + struct static_mod *sm = 0; + int len = std_strlen(uri) + 1; + VERIFYC(NULL != (sm = ((struct static_mod*)calloc(1, sizeof(struct static_mod) + len))), AEE_ENOMEMORY); + std_strlcpy(sm->uri, uri, len); + sm->invoke = invoke; + sm->handle_invoke = handle_invoke; + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ADD_STR(*tbl, uri, sm); + RW_MUTEX_UNLOCK_WRITE(me->mut); +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: static module addition failed\n", nErr); + if(sm) { + free(sm); + sm = NULL; + } + } + return nErr; +} + +static int static_mod_table_register_static_override(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticModOverrides, uri, pfn, 0); +} +static int static_mod_table_register_static_override1(struct static_mod_table* me, const char* uri, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticModOverrides, uri, 0, pfn); +} +static int static_mod_table_register_static(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticMods, uri, pfn, 0); +} +static int static_mod_table_register_static1(struct static_mod_table* me, const char* uri, int(*pfn)(remote_handle64,uint32 sc, remote_arg* pra)) { + return static_mod_add(me, &me->staticMods, uri, 0, pfn); +} + + +static int static_mod_table_register_const_handle(struct static_mod_table* me, remote_handle local, + remote_handle64 remote, const char* uri, + int(*invoke)(uint32 sc, remote_arg* pra), + int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra) + ) { + int nErr = AEE_SUCCESS; + int len = std_strlen(uri) + 1; + struct const_mod *dm = 0, *dmOld; + VERIFYC(NULL != (dm = ((struct const_mod*)calloc(1, sizeof(struct open_mod) + len))), AEE_ENOMEMORY); + dm->key = local; + dm->invoke = invoke; + dm->handle_invoke = handle_invoke; + dm->h64 = remote; + std_strlcpy(dm->uri, uri, len); + + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_FIND_INT(me->constMods, &local, dmOld); + if(dmOld == 0) { + HASH_ADD_INT(me->constMods, key, dm); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + nErr = dmOld != 0 ? -1 : nErr; +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: failed to register const handle in modtable\n", nErr); + if(dm) { + free(dm); + dm = NULL; + } + } + return nErr; +} + +static int open_mod_handle_open(struct open_mod *mod, const char* name, + remote_handle64 *ph) { + int nErr = AEE_SUCCESS; + remote_arg args[3]; + int32_t len = strlen(name) + 1; + args[0].buf.pv = &len; + args[0].buf.nLen = sizeof(len); + args[1].buf.pv = (void*)name; + args[1].buf.nLen = len; + nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,0,2,0,0,1),args); + if(!nErr) { + *ph = args[2].h64; + } + FARF(HIGH, "allocated %x", *ph); + return nErr; +} + +static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h) { + int nErr; + remote_arg args[1]; + args[0].h64 = h; + FARF(HIGH, "releasing %x", h); + nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,1,0,0,1,0),args); + return nErr; +} + +static int notqmark(struct sbuf *buf) { + return sbuf_notchar(buf, '?'); +} +static int notandoreq(struct sbuf *buf) { + return sbuf_notchars(buf, "&="); +} +static int notand(struct sbuf *buf) { + return sbuf_notchar(buf, '&'); +} + +static int parse_uri(const char *uri, int urilen, struct parsed_uri *out) { +// "file:///librhtest_skel.so?rhtest_skel_handle_invoke&_modver=1.0" + int nErr = 0; + char *name, *value; + int nameLen, valueLen; + struct sbuf buf; + FARF(HIGH, "parse_uri %s %d", uri, urilen); + memset(out, 0, sizeof(*out)); + //initialize + sbuf_parser_init(&buf, uri, urilen); + + //parse until question mark + VERIFYC(sbuf_string(&buf, "file://"), AEE_EINVALIDFORMAT); + + //ignore the starting / + (void)sbuf_string(&buf, "/"); + + out->file = sbuf_cur(&buf); + VERIFY(sbuf_many1(&buf, notqmark)); + out->filelen = sbuf_cur(&buf) - out->file; + FARF(HIGH, "file:%.*s %d", out->filelen, out->file, out->filelen); + VERIFY(sbuf_char(&buf, '?')); + out->sym = sbuf_cur(&buf); + VERIFY(sbuf_many1(&buf, notand)); + out->symlen = sbuf_cur(&buf) - out->sym; + assert(out->sym + out->symlen <= uri + urilen); + FARF(HIGH, "sym:%.*s %d", out->symlen, out->sym, out->symlen); + + if(!sbuf_end(&buf) && sbuf_char(&buf, '&')) { + //parse each query + while(!sbuf_end(&buf)) { + //record where the name starts + name = sbuf_cur(&buf); + + //name is valid until '=' or '&' + VERIFY(sbuf_many1(&buf, notandoreq)); + nameLen = sbuf_cur(&buf) - name; + + value = 0; + valueLen = 0; + //if the next char is a '=' then we also get a value + if(sbuf_char(&buf, '=')) { + value = sbuf_cur(&buf); + + //value is until the next query that starts with '&' + VERIFY(sbuf_many1(&buf, notand)); + valueLen = sbuf_cur(&buf) - value; + } + //expect '&' or end + sbuf_char(&buf, '&'); + if(!std_strncmp(name, "_modver", nameLen)) { + out->ver = value; + out->verlen = valueLen; + } + } + } +bail: + if(out->filelen) { + FARF(HIGH, "parse_uri file: %.*s", out->filelen, out->file); + } + if(out->symlen) { + FARF(HIGH, "parse_uri sym: %.*s", out->symlen, out->sym); + } + if(out->verlen) { + FARF(HIGH, "parse_uri version: %.*s", out->verlen, out->ver); + } + FARF(HIGH, "parse_uri done: %s %d err:%x", uri, urilen, nErr); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: parseuri failed for uri %s, urilen %d\n", nErr, uri, urilen); + } + return nErr; +} + +static int open_mod_table_open_dynamic(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlStr, int dlerrorLen, int* pdlErr) +{ + int nErr = AEE_SUCCESS, dlErr = 0; + struct open_mod *dm = 0, *dmOld; + int len = strlen(uri); + int tmplen = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; + char *tmp = 0; + FARF(HIGH, "open_mod_table_open_dynamic"); + VERIFYC(NULL != (tmp = calloc(1, tmplen)), AEE_ENOMEMORY); + VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(struct open_mod) + len + 1))), AEE_ENOMEMORY); + std_memmove(dm->uri, uri, len + 1); + FARF(HIGH, "calling parse_uri"); + (void)parse_uri(dm->uri, len, &dm->vals); + FARF(HIGH, "done calling parse_uri"); + FARF(HIGH, "vals %d %d %d", dm->vals.filelen, dm->vals.symlen, dm->vals.verlen); + if(dm->vals.filelen) { + int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.filelen, dm->vals.file); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } else { + int rv; + rv = std_snprintf(tmp, tmplen, "lib%s_skel.so", uri); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } + FARF(HIGH, "calling dlopen for %s", tmp); + dm->dlhandle = DLOPEN(tmp,RTLD_NOW); + FARF(HIGH, "got %p for dlopen %s", dm->dlhandle, tmp); + VERIFY(!(nErr = (dlErr = dm->dlhandle == 0 ? -5 : 0))); + + if(dm->vals.symlen) { + int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.symlen, dm->vals.sym); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } else { + int rv = std_snprintf(tmp, tmplen, "%s_skel_invoke", uri); + VERIFYC(tmplen >= rv, AEE_EBADSIZE); + } + + FARF(HIGH, "calling dlsym for %s", tmp); + if(dm->vals.verlen && 0 == std_strncmp(dm->vals.ver, "1.0", dm->vals.verlen)) { + dm->handle_invoke = (handle_invoke_fn) DLSYM(dm->dlhandle, tmp); + } else { + dm->invoke = (invoke_fn) DLSYM(dm->dlhandle, tmp); + } + FARF(HIGH, "dlsym returned %p %p", dm->invoke, dm->handle_invoke); + VERIFYC(!(dlErr = dm->invoke || dm->handle_invoke ? 0 : AEE_ENOSUCHSYMBOL), AEE_ENOSUCHSYMBOL); + + dm->key = (uint32)(uintptr_t)dm; + dm->refs = 1; + if(dm->handle_invoke) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); + } + RW_MUTEX_LOCK_WRITE(me->mut); + do { + HASH_FIND_INT(me->openMods, &dm->key, dmOld); + if(dmOld) { + dm->key++; + } + } while(dmOld); + RW_MUTEX_LOCK_WRITE(me->smt->mut); + HASH_FIND_INT(me->smt->constMods, &dm->key, dmOld); + RW_MUTEX_UNLOCK_WRITE(me->smt->mut); + if(dmOld == 0) { + HASH_ADD_INT(me->openMods, key, dm); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + nErr = dmOld != 0 ? -1 : nErr; + if(nErr == 0) { + *handle = dm->key; + } +bail: + if (nErr != AEE_SUCCESS) { + if(dlErr) { + const char* dlerr = DLERROR(); + if(dlerr != 0){ + std_strlcpy(dlStr,dlerr,dlerrorLen); + } + FARF(HIGH, "dlerror:%x:%s", dlErr, dlerr == 0 ? "" : dlerr); + nErr = 0; + } + if(pdlErr) { + *pdlErr = dlErr; + } + if(dm && dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(dm && dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + if(dm) { + free(dm); + dm = NULL; + } + VERIFY_EPRINTF("Error %x: open modtable dynamic failed. dlerr %x\n", nErr, dlErr); + } + FARF(HIGH, "done open_mod_table_open_dynamic for %s rv %x handle: %p %x", uri, nErr, *handle, dlErr); + if(tmp) { + free(tmp); + tmp = NULL; + } + return nErr; +} + +static int open_mod_table_open_from_static(struct open_mod_table* me, + struct static_mod** tbl, + const char* uri, + remote_handle* handle) +{ + int nErr = AEE_SUCCESS; + struct static_mod *sm = 0; + struct open_mod *dm = 0, *dmOld = 0; + int len = std_strlen(uri); + int sz = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; + char *tmp = 0; + VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(*dm) + sz))), AEE_ENOMEMORY); + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_STR(*tbl, uri, sm); + RW_MUTEX_UNLOCK_READ(me->mut); + std_memmove(dm->uri, uri, len); + if(sm == 0) { + VERIFY(AEE_SUCCESS == (nErr = parse_uri(uri, len, &dm->vals))); + FARF(HIGH, "file %.*s %d", dm->vals.filelen, dm->vals.file, dm->vals.filelen); + FARF(HIGH, "sym %.*s %d", dm->vals.symlen, dm->vals.sym, dm->vals.symlen); + FARF(HIGH, "version %.*s %d", dm->vals.verlen, dm->vals.ver, dm->vals.verlen); + if(dm->vals.verlen) { + int rv = std_snprintf(dm->uri, sz, "file:///%.*s?%.*s&_modver=%.*s", + dm->vals.filelen, dm->vals.file, + dm->vals.symlen, dm->vals.sym, + dm->vals.verlen, dm->vals.ver); + VERIFYC(sz >= rv, AEE_EBADSIZE); + } else { + int rv = std_snprintf(dm->uri, sz, "file://%.*s?%.*s", + dm->vals.filelen, dm->vals.file, + dm->vals.symlen, dm->vals.sym); + VERIFYC(sz >= rv, AEE_EBADSIZE); + } + FARF(HIGH, "dm->uri:%s", dm->uri); + + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_STR(*tbl, dm->uri, sm); + RW_MUTEX_UNLOCK_READ(me->mut); + } + VERIFYC(0 != sm, AEE_ENOTINITIALIZED); + assert(sm->handle_invoke || sm->invoke); + dm->handle_invoke = sm->handle_invoke; + dm->invoke = sm->invoke; + dm->key = (uint32)(uintptr_t)dm; + dm->refs = 1; + if(dm->handle_invoke) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); + } + + RW_MUTEX_LOCK_WRITE(me->mut); + do { + HASH_FIND_INT(me->openMods, &dm->key, dmOld); + if(dmOld) { + dm->key++; + } + } while(dmOld); + HASH_ADD_INT(me->openMods, key, dm); + RW_MUTEX_UNLOCK_WRITE(me->mut); + + *handle = dm->key; +bail: + if(tmp) { + free(tmp); + tmp = NULL; + } + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable open from static failed.\n", nErr); + } + if(nErr && dm) { + if(dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + free(dm); + dm = NULL; + } + return nErr; +} + +static int open_mod_table_open(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr) +{ + int nErr = AEE_SUCCESS, dlErr = 0; + if(pdlErr) { + *pdlErr = 0; + } + if(0 != open_mod_table_open_static_override(me, uri, handle)) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open_dynamic(me, uri, handle, dlerr, dlerrorLen, &dlErr))); + if(dlErr != 0) { + FARF(HIGH, "dynammic open failed, trying static"); + if(0 != open_mod_table_open_static(me, uri, handle)) { + if(pdlErr) { + *pdlErr = dlErr; + } + } + } + } +bail: + FARF(HIGH, "done open for %s rv %d handle: %p", uri, nErr, *handle); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: open modtable failed\n", nErr); + } + return nErr; +} + +static void open_mod_close(struct open_mod_table *me, struct open_mod* dm) { + RW_MUTEX_LOCK_WRITE(me->mut); + dm->refs--; + if(dm->refs <= 0) { + HASH_DEL(me->openMods,dm); + } else { + dm = 0; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + if(dm) { + if(dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + free(dm); + dm = NULL; + } +} +static int open_mod_table_close(struct open_mod_table* me, remote_handle64 handle, char* errStr, int errStrLen, int* pdlErr) +{ + int nErr = AEE_SUCCESS; + struct open_mod *dm, *del = 0;; + int dlErr = 0; + // First ensure that the handle is valid + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_FIND_INT(me->openMods, &handle, dm); + if(dm) { + dm->refs--; + if(dm->refs <= 0) { + del = dm; + FARF(HIGH, "deleting %s %p", del->uri, del); + HASH_DEL(me->openMods,dm); + } else { + FARF(HIGH, "leaked %s", dm->uri); + dm = 0; + } + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + if(del) { + if(del->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if(del->dlhandle) { + dlErr = DLCLOSE(del->dlhandle); + } + FARF(HIGH, "free %s %p", del->uri, del); + free(del); + del = NULL; + } + VERIFY(del); + +bail: + if(dlErr) { + const char* error = DLERROR(); + nErr = dlErr; + if(error != 0){ + std_strlcpy(errStr,error,errStrLen); + } + VERIFY_EPRINTF("Error %x: open modtable close failed. dlerr %s\n", nErr, error); + } + if(pdlErr) { + *pdlErr = dlErr; + } + return nErr; +} + +static struct open_mod* open_mod_table_get_open(struct open_mod_table* me, remote_handle handle) { + struct open_mod* om = 0; + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_INT(me->openMods, &handle, om); + if(0 != om) { + om->refs++; + } + RW_MUTEX_UNLOCK_READ(me->mut); + return om; +} +static struct const_mod* open_mod_table_get_const(struct open_mod_table* me, remote_handle handle) { + struct const_mod* cm = 0; + RW_MUTEX_LOCK_READ(me->smt->mut); + HASH_FIND_INT(me->smt->constMods, &handle, cm); + RW_MUTEX_UNLOCK_READ(me->smt->mut); + return cm; +} + +static int open_mod_table_handle_invoke(struct open_mod_table* me, remote_handle handle, uint32 sc, remote_arg* pra) { + int nErr = AEE_SUCCESS; + struct open_mod* om = 0; + struct const_mod* cm = 0; + remote_handle64 h = 0; + invoke_fn invoke = 0; + handle_invoke_fn handle_invoke = 0; + cm = open_mod_table_get_const(me, handle); + if(cm) { + invoke = cm->invoke; + handle_invoke = cm->handle_invoke; + h = cm->h64; + } else { + VERIFYC(0 != (om = open_mod_table_get_open(me, handle)), AEE_ENOSUCHMOD); + invoke = om->invoke; + handle_invoke = om->handle_invoke; + h = om->h64; + } + if(invoke) { + VERIFY(AEE_SUCCESS == (nErr = invoke(sc, pra))); + } else { + VERIFY(AEE_SUCCESS == (nErr = handle_invoke(h, sc, pra))); + } +bail: + if(om) { + open_mod_close(me, om); + } + FARF(HIGH, "invoke rv %p %x %x", handle, sc, nErr); + return nErr; +} + +struct mod_table { + struct static_mod_table smt; + struct open_mod_table omt; +}; + +// mod_table object +static struct static_mod_table static_mod_table_obj; + + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * overrides will be tried first, then dynamic modules, then regular + * static modules. + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static_override(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static_override(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + +int mod_table_register_static_override1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static_override1(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + +int mod_table_register_static1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static1(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + + +/** + * Open a module and get a handle to it + * + * uri, name of module to open + * handle, Output handle + * dlerr, Error String (if an error occurs) + * dlerrorLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_open(const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr) { + int nErr = AEE_SUCCESS; + struct open_mod_table* pomt = 0; + FARF(HIGH, "mod_table_open for %s", uri); + VERIFY(AEE_SUCCESS == (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, sizeof(*pomt), open_mod_table_ctor_imp, (void*)&static_mod_table_obj, open_mod_table_dtor_imp, (void**)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open(pomt,uri,handle,dlerr,dlerrorLen,pdlErr))); +bail: + FARF(HIGH, "mod_table_open for %s nErr: %x", uri, nErr); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable open failed\n", nErr); + } + return nErr; +} +/** + * invoke a handle in the mod table + * + * handle, handle to invoke + * sc, scalars, see remote.h for documentation. + * pra, args, see remote.h for documentation. + */ +int mod_table_invoke(remote_handle handle, uint32 sc, remote_arg* pra) { + int nErr = AEE_SUCCESS; + struct open_mod_table* pomt = 0; + VERIFY(AEE_SUCCESS == (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, sizeof(*pomt), open_mod_table_ctor_imp, (void*)&static_mod_table_obj, open_mod_table_dtor_imp, (void**)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_handle_invoke(pomt, handle, sc, pra))); +bail: + return nErr; +} + +/** + * Closes a handle in the mod table + * + * handle, handle to close + * errStr, Error String (if an error occurs) + * errStrLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_close(remote_handle handle, char* errStr, int errStrLen, int* pdlErr) { + int nErr = AEE_SUCCESS; + struct open_mod_table* pomt = 0; + VERIFY(AEE_SUCCESS == (nErr = HAP_pls_lookup((uintptr_t)open_mod_table_ctor_imp, 0, (void**)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_close(pomt, handle, errStr,errStrLen,pdlErr))); +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable close failed\n", nErr); + } + return nErr; +} + +/** + * internal use only + */ +int mod_table_register_const_handle(remote_handle remote, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_const_handle(&static_mod_table_obj, remote, 0, uri, pfn, 0); + } + return AEE_EUNKNOWN; +} +int mod_table_register_const_handle1(remote_handle remote, remote_handle64 local, const char* uri, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { + if(0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_const_handle(&static_mod_table_obj, remote, local, uri, 0, pfn); + } + return AEE_EUNKNOWN; +} + +// Constructor and destructor +static int mod_table_ctor(void) { + return static_mod_table_ctor(&static_mod_table_obj); +} +static void mod_table_dtor(void) { + static_mod_table_dtor_imp(&static_mod_table_obj); + return; +} + +PL_DEFINE(mod_table, mod_table_ctor, mod_table_dtor); diff --git a/src/pl_list.c b/src/pl_list.c new file mode 100644 index 0000000..fc2dd90 --- /dev/null +++ b/src/pl_list.c @@ -0,0 +1,40 @@ +/* + * 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 "platform_libs.h" + +PL_DEP(gpls) +PL_DEP(listener_android) + +struct platform_lib* (*pl_list[])(void) = { + PL_ENTRY(gpls), + PL_ENTRY(listener_android), + 0 +}; + + diff --git a/src/platform_libs.c b/src/platform_libs.c new file mode 100644 index 0000000..4cd576b --- /dev/null +++ b/src/platform_libs.c @@ -0,0 +1,121 @@ +/* + * 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. + */ +#define FARF_ERROR 1 +#include "HAP_farf.h" +#include "platform_libs.h" +#include "AEEatomic.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include <stdio.h> +#include <assert.h> +#include "verify.h" + +extern struct platform_lib* (*pl_list[])(void); +static uint32 atomic_IfNotThenAdd(uint32* volatile puDest, uint32 uCompare, int nAdd); + +int pl_lib_init(struct platform_lib* (*plf)(void)) { + int nErr = AEE_SUCCESS; + struct platform_lib* pl = plf(); + if(1 == atomic_Add(&pl->uRefs, 1)) { + if(pl->init) { + FARF(HIGH, "calling init for %s",pl->name); + nErr = pl->init(); + FARF(HIGH, "init for %s returned %x",pl->name, nErr); + } + pl->nErr = nErr; + } + if(pl->nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: %s init failed", nErr, pl->name); + } + return pl->nErr; +} + +void pl_lib_deinit(struct platform_lib* (*plf)(void)) { + struct platform_lib* pl = plf(); + if(1 == atomic_IfNotThenAdd(&pl->uRefs, 0, -1)) { + if(pl->deinit && pl->nErr == 0) { + pl->deinit(); + } + } + return; +} + +static int pl_init_lst(struct platform_lib* (*lst[])(void)) { + int nErr = AEE_SUCCESS; + int ii; + for(ii = 0; lst[ii] != 0; ++ii) { + nErr = pl_lib_init(lst[ii]); + if(nErr != 0) { + break; + } + } + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: plinit failed\n", nErr); + } + return nErr; + +} +int pl_init(void) { + int nErr = pl_init_lst(pl_list); + return nErr; +} + +static void pl_deinit_lst(struct platform_lib* (*lst[])(void)) { + int size, ii; + for(size = 0; lst[size] != 0; ++size) {;} + for(ii = size - 1; ii >= 0; --ii) { + pl_lib_deinit(lst[ii]); + } + return; +} + + +void pl_deinit(void) { + pl_deinit_lst(pl_list); + return; +} + +static uint32 atomic_IfNotThenAdd(uint32* volatile puDest, uint32 uCompare, int nAdd) +{ + uint32 uPrev; + uint32 uCurr; + do { + //check puDest + uCurr = *puDest; + uPrev = uCurr; + //see if we need to update it + if(uCurr != uCompare) { + //update it + uPrev = atomic_CompareAndExchange(puDest, uCurr + nAdd, uCurr); + } + //verify that the value was the same during the update as when we decided to update + } while(uCurr != uPrev); + return uPrev; +} + diff --git a/src/remote_priv.h b/src/remote_priv.h new file mode 100644 index 0000000..60b4cd2 --- /dev/null +++ b/src/remote_priv.h @@ -0,0 +1,42 @@ +/* + * 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. + */ +#ifndef REMOTE_PRIV_H +#define REMOTE_PRIV_H + +#include "remote64.h" + +// Number of domains extended to include sessions +// Domain ID extended (0 - 3): Domain id (0 - 3), session id 0 +// Domain ID extended (4 - 7): Domain id (0 - 3), session id 1 +#define NUM_DOMAINS_EXTEND (NUM_DOMAINS * NUM_SESSIONS) + +#define FASTRPC_SESSION_ID1 (4) +#define FASTRPC_SESSION_URI "&_session=1" + +#endif // REMOTE_PRIV_H diff --git a/src/remotectl_stub.c b/src/remotectl_stub.c new file mode 100644 index 0000000..eabb7da --- /dev/null +++ b/src/remotectl_stub.c @@ -0,0 +1,656 @@ +/* + * 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. + */ +#ifndef _REMOTECTL_STUB_H +#define _REMOTECTL_STUB_H +#include "remotectl.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include <stdio.h> + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#include <string.h> +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include <stdlib.h> +#include <stdint.h> + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include <stdint.h> + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _REMOTECTL_SLIM_H +#define _REMOTECTL_SLIM_H +#include "remote.h" +#include <stdint.h> + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[2]; +static const Type types[2] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4}}; +static const Parameter parameters[6] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[11] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[1])),(&(parameters[3])),(&(parameters[2])),(&(parameters[1])),(&(parameters[3])),(&(parameters[5])),(&(parameters[4])),(&(parameters[4]))}; +static const Method methods[4] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x8,0x8,6,4,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[4])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[9])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x8,0x0,3,2,(&(parameterArrays[7])),0x4,0x0}}; +static const Method* const methodArrays[4] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3])}; +static const char strings[83] = "set_param\0grow_heap\0phyAddr\0dlerror\0params\0handle\0reqID\0nSize\0close\0nErr\0name\0open\0"; +static const uint16_t methodStrings[15] = {78,73,43,28,68,62,43,28,68,0,50,36,10,20,56}; +static const uint16_t methodStringsArrays[4] = {0,5,12,9}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(remotectl_slim) = {4,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_REMOTECTL_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_remotectl_handle +#define _const_remotectl_handle ((remote_handle)-1) +#endif //_const_remotectl_handle + +static void _remotectl_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_remotectl_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_remotectl_handle; + } +} + +static int _remotectl_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_remotectl_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _remotectl_handle(void) { + remote_handle* ph; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_remotectl_handle, 0, sizeof(*ph), _remotectl_pls_ctor, "remotectl", _remotectl_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_remotectl_handle, 0, sizeof(*ph), _remotectl_pls_ctor, "remotectl", _remotectl_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _remotectl_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#include "Windows.h" +uint32_t _remotectl_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _remotectl_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _remotectl_handle(void) { + static remote_handle handle = _const_remotectl_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _remotectl_pls_ctor("remotectl", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_remotectl_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _remotectl_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle_invoke)(_remotectl_handle(), _sc, _pra); +} + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +extern int remote_register_dma_handle(int, uint32_t); +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, char* _in0[1], uint32_t _rout1[1], char* _rout2[1], uint32_t _rout2Len[1], uint32_t _rout3[1]) { + uint32_t _in0Len[1]; + int _numIn[1]; + remote_arg _pra[4]; + uint32_t _primIn[2]; + uint32_t _primROut[2]; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _numIn[0] = 1; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _in0Len[0] = (1 + strlen(_in0[0])); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _COPY(_primIn, 4, _rout2Len, 0, 4); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout2[0]; + _praROut[0].buf.nLen = (1 * _rout2Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _COPY(_rout3, 0, _primROut, 4, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_open)(const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + return _stub_method(_remotectl_handle(), _mid, (char**)&name, (uint32_t*)handle, (char**)&dlerror, (uint32_t*)&dlerrorLen, (uint32_t*)nErr); +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], char* _rout1[1], uint32_t _rout1Len[1], uint32_t _rout2[1]) { + int _numIn[1]; + remote_arg _pra[3]; + uint32_t _primIn[2]; + uint32_t _primROut[1]; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _rout1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout1[0]; + _praROut[0].buf.nLen = (1 * _rout1Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout2, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_close)(int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + return _stub_method_1(_remotectl_handle(), _mid, (uint32_t*)&handle, (char**)&dlerror, (uint32_t*)&dlerrorLen, (uint32_t*)nErr); +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1]) { + remote_arg _pra[1]; + uint32_t _primIn[2]; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_grow_heap)(uint32 phyAddr, uint32 nSize) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method_2(_remotectl_handle(), _mid, (uint32_t*)&phyAddr, (uint32_t*)&nSize); +} +static __inline int _stub_method_3(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], char* _in1[1], uint32_t _in1Len[1]) { + remote_arg _pra[2]; + uint32_t _primIn[2]; + remote_arg* _praIn; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = _in1[0]; + _praIn[0].buf.nLen = (4 * _in1Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_set_param)(int reqID, const uint32* params, int paramsLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_3(_remotectl_handle(), _mid, (uint32_t*)&reqID, (char**)¶ms, (uint32_t*)¶msLen); +} +#ifdef __cplusplus +} +#endif +#endif //_REMOTECTL_STUB_H diff --git a/src/rpcmem_android.c b/src/rpcmem_android.c new file mode 100644 index 0000000..ecac123 --- /dev/null +++ b/src/rpcmem_android.c @@ -0,0 +1,183 @@ +/* + * 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 "rpcmem.h" +#include "verify.h" +#include "fastrpc_internal.h" +#include "AEEQList.h" +#include "AEEstd.h" +#include "apps_std.h" + +#include <stdlib.h> +#include <stdio.h> +#include <pthread.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <errno.h> + +#define PAGE_SIZE 4096 +#define PAGE_MASK ~((uintptr_t)PAGE_SIZE - 1) + +static QList rpclst; +static pthread_mutex_t rpcmt; +struct rpc_info +{ + QNode qn; + void *buf; + void *aligned_buf; + int size; + int fd; +}; + +extern int open_device_node(int domain); +static int rpcmem_open_dev() +{ + return open_device_node(3); +} + +void rpcmem_init() +{ + int fd; + QList_Ctor(&rpclst); + pthread_mutex_init(&rpcmt, 0); +} + +void rpcmem_deinit() +{ + pthread_mutex_destroy(&rpcmt); +} + +int rpcmem_to_fd_internal(void *po) { + struct rpc_info *rinfo, *rfree = 0; + QNode *pn, *pnn; + + pthread_mutex_lock(&rpcmt); + QLIST_NEXTSAFE_FOR_ALL(&rpclst, pn, pnn) + { + rinfo = STD_RECOVER_REC(struct rpc_info, qn, pn); + if (rinfo->aligned_buf == po) + { + rfree = rinfo; + break; + } + } + pthread_mutex_unlock(&rpcmt); + + if (rfree) + return rfree->fd; + + return -1; +} + +int rpcmem_to_fd(void *po) { + return rpcmem_to_fd_internal(po); +} + + +void *rpcmem_alloc_internal(int heapid, uint32 flags, int size) +{ + struct rpc_info *rinfo; + struct fastrpc_alloc_dma_buf buf; + int nErr = 0; + (void)heapid; + (void)flags; + int dev = rpcmem_open_dev(); + + VERIFY(0 != (rinfo = calloc(1, sizeof(*rinfo)))); + + buf.size = size + PAGE_SIZE; + buf.fd = -1; + buf.flags = 0; + + VERIFY((0 == ioctl(dev, FASTRPC_IOCTL_ALLOC_DMA_BUFF, (unsigned long)&buf)) || errno == ENOTTY); + VERIFY(0 != (rinfo->buf = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, buf.fd, 0))); + rinfo->fd = buf.fd; + rinfo->aligned_buf = (void *)(((uintptr_t)rinfo->buf /*+ PAGE_SIZE*/) & PAGE_MASK); + rinfo->aligned_buf = rinfo->buf; + rinfo->size = size; + pthread_mutex_lock(&rpcmt); + QList_AppendNode(&rpclst, &rinfo->qn); + pthread_mutex_unlock(&rpcmt); + + return rinfo->aligned_buf; +bail: + if (nErr) + { + if (rinfo) + { + if (rinfo->buf) + { + free(rinfo->buf); + } + free(rinfo); + } + } + return 0; +} + +void rpcmem_free_internal(void *po) +{ + struct rpc_info *rinfo, *rfree = 0; + QNode *pn, *pnn; + int nErr = 0; + + pthread_mutex_lock(&rpcmt); + QLIST_NEXTSAFE_FOR_ALL(&rpclst, pn, pnn) + { + rinfo = STD_RECOVER_REC(struct rpc_info, qn, pn); + if (rinfo->aligned_buf == po) + { + rfree = rinfo; + QNode_Dequeue(&rinfo->qn); + break; + } + } + pthread_mutex_unlock(&rpcmt); + if (rfree) + { + int dev = rpcmem_open_dev(); + + munmap(rfree->buf, rfree->size); + free(rfree); + } +bail: + return; + +} + +void rpcmem_free(void* po) { + rpcmem_free_internal(po); +} + +void* rpcmem_alloc(int heapid, uint32 flags, int size) { + return rpcmem_alloc_internal(heapid, flags, size); +} diff --git a/src/smath.c b/src/smath.c new file mode 100644 index 0000000..f7fb28b --- /dev/null +++ b/src/smath.c @@ -0,0 +1,54 @@ +/* + * 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 "AEEStdDef.h" +#include "AEEsmath.h" + + +static int32 ToInt(int64 a) +{ + return (a > MAX_INT32 ? MAX_INT32 : + a < MIN_INT32 ? MIN_INT32 : + (int32)a); +} + +int smath_Add(int a, int b) +{ + return ToInt((int64)a + (int64)b); +} + +int smath_Sub(int a, int b) +{ + return ToInt((int64)a - (int64)b); +} + +int smath_Mul(int a, int b) +{ + return ToInt((int64)a * (int64)b); +} diff --git a/src/std.c b/src/std.c new file mode 100644 index 0000000..d369d99 --- /dev/null +++ b/src/std.c @@ -0,0 +1,570 @@ +/** + * 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. + */ + +/* +======================================================================= + +FILE: std.c + +SERVICES: apiOne std lib string stuff + +======================================================================= +*/ + +// +// someday, drop this #include, implement our own memmove() +// +#include <stddef.h> +#include "AEEstd.h" +#include "version.h" + +int std_getversion(char *pcDst, int nDestSize) +{ + return std_strlcpy(pcDst, VERSION_STRING, nDestSize); +} + + +char std_tolower(char c) +{ + if ((c >= 'A') && (c <= 'Z')) { + c |= 32; + } + return c; +} + +char std_toupper(char c) +{ + if ((c >= 'a') && (c <= 'z')) { + c &= ~32; + } + return c; +} + + +static __inline int x_casecmp(unsigned char c1, unsigned char c2) +{ + int diff = c1 - c2; + if (c1 >= 'A' && c1 <= 'Z') { + diff += 32; + } + if (c2 >= 'A' && c2 <= 'Z') { + diff -= 32; + } + return diff; +} + + +int std_strncmp(const char* s1, const char* s2, int n) +{ + if (n > 0) { + int i = 0; + + do { + unsigned char c1 = (unsigned char)s1[i]; + unsigned char c2 = (unsigned char)s2[i]; + int diff = c1 - c2; + + if (diff) { + return diff; + } + + if ('\0' == c1) { + break; + } + i++; + } while (i < n); + } + + return 0; +} + +int std_strcmp(const char* s1, const char* s2) +{ + return std_strncmp(s1, s2, MAX_INT32); +} + +int std_strnicmp(const char* s1, const char* s2, int n) +{ + if (n > 0) { + int i = -n; + + s1 += n; + s2 += n; + + do { + unsigned char c1 = (unsigned char)s1[i]; + unsigned char c2 = (unsigned char)s2[i]; + + int diff = x_casecmp(c1,c2); + if (diff) { + return diff; + } + if ('\0' == c1) { + break; + } + } while (++i); + } + return 0; +} + +int std_stricmp(const char* s1, const char* s2) +{ + return std_strnicmp(s1, s2, MAX_INT32); +} + +int std_strlcpy(char* pcDst, const char* cpszSrc, int nDestSize) +{ + int nLen = std_strlen(cpszSrc); + + if (0 < nDestSize) { + int n; + + n = STD_MIN(nLen, nDestSize - 1); + (void)std_memmove(pcDst, cpszSrc, n); + + pcDst[n] = 0; + } + + return nLen; +} + +int std_strlcat(char* pcDst, const char* cpszSrc, int nDestSize) +{ + int nLen = 0; + + while ((nLen < nDestSize) && (0 != pcDst[nLen])) { + ++nLen; + } + + return nLen + std_strlcpy(pcDst+nLen, cpszSrc, nDestSize-nLen); +} + +char* std_strstr(const char* cpszHaystack, const char* cpszNeedle) +{ + /* Check the empty needle string as a special case */ + if ('\0' == *cpszNeedle ) { + return (char*)cpszHaystack; + } + + while ('\0' != *cpszHaystack) { + /* Find the first character of the needle string in the haystack string */ + if (*cpszHaystack == *cpszNeedle) { + /* check if the rest of the string matches */ + const char* pHaystack = cpszHaystack; + const char* pNeedle = cpszNeedle; + do { + if ('\0' == *++pNeedle) { + /* Found a match */ + return (char*)cpszHaystack; + } + } while (*++pHaystack == *pNeedle); + } + cpszHaystack++; + } + + return 0; +} + + +int std_memcmp(const void* p1, const void* p2, int length) +{ + const unsigned char *cpc1 = p1; + const unsigned char *cpc2 = p2; + + while (length-- > 0) { + int diff = *cpc1++ - *cpc2++; + + if (0 != diff) { + return diff; + } + } + return 0; +} + +int std_wstrlen(const AECHAR* s) +{ + const AECHAR *sEnd = s; + + if (! *sEnd) + return 0; + + do { + ++sEnd; + } while (*sEnd); + + return sEnd - s; +} + + +int std_wstrlcpy(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize) +{ + int nLen = std_wstrlen(cpwszSrc); + + if (0 < nDestSize) { + int n; + + n = STD_MIN(nLen, nDestSize - 1); + /* call memmove, in case n is larger than 1G */ + (void)std_memsmove(pwcDst, nDestSize*sizeof(AECHAR), + cpwszSrc, ((size_t)n)*sizeof(AECHAR)); + + pwcDst[n] = 0; + } + + return nLen; +} + +int std_wstrlcat(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize) +{ + int nLen = 0; + + while ((nLen < nDestSize) && (0 != pwcDst[nLen])) { + ++nLen; + } + + return nLen + std_wstrlcpy(pwcDst+nLen, cpwszSrc, nDestSize-nLen); +} + +char* std_strchrend(const char* cpsz, char c) +{ + while (*cpsz && *cpsz != c) { + ++cpsz; + } + return (char*)cpsz; +} + +char* std_strchr(const char* cpszSrch, int c) +{ + const char *pc = std_strchrend(cpszSrch, (char)c); + + return (*pc == c ? (char*)pc : 0); +} + +void* std_memstr(const char* cpHaystack, const char* cpszNeedle, + int nHaystackLen) +{ + int nLen = 0; + + /* Handle empty needle string as a special case */ + if ('\0' == *cpszNeedle ) { + return (char*)cpHaystack; + } + + /* Find the first character of the needle string in the haystack string */ + while (nLen < nHaystackLen) { + if (cpHaystack[nLen] == *cpszNeedle) { + /* check if the rest of the string matches */ + const char* cpNeedle = cpszNeedle; + int nRetIndex = nLen; + do { + if ('\0' == *++cpNeedle) { + /* Found a match */ + return (void*)(cpHaystack + nRetIndex); + } + nLen++; + } while(cpHaystack[nLen] == *cpNeedle); + } + else { + nLen++; + } + } + + return 0; +} + +void* std_memchrend(const void* p, int c, int nLen) +{ + const char* cpc = (const char*)p + nLen; + int i = -nLen; + + if (nLen > 0) { + do { + if (cpc[i] == c) { + break; + } + } while (++i); + } + return (void*) (cpc + i); +} + +void* std_memchr(const void* s, int c, int n) +{ + const char *pEnd = (const char*)std_memchrend(s,c,n); + int nEnd = pEnd - (const char*)s; + + if (nEnd < n) { + return (void*)pEnd; + } + return 0; +} + +void* std_memrchr(const void* p, int c, int nLen) +{ + const char* cpc = (const char*)p - 1; + + if (nLen > 0) { + do { + if (cpc[nLen] == c) { + return (void*) (cpc + nLen); + } + } while (--nLen); + } + + return 0; +} + + +char* std_strrchr(const char* cpsz, int c) +{ + return std_memrchr(cpsz, c, std_strlen(cpsz) + 1); +} + + +void* std_memrchrbegin(const void* p, int c, int n) +{ + void *pOut = std_memrchr(p, c, n); + + return (pOut ? pOut : (void*)p); +} + + +// x_scanbytes: internal function; WARNING: nLen must be >0 +// +// cStop = character at which to stop (in addition to cpszChars[...]) +// +// Using a bit mask provides a constant-time check for a terminating +// character: 10 instructions for inner loop on ADS12arm9. Initialization +// overhead is increased, but this is quickly made up for as searching begins. +// +// +static char *x_scanbytes(const char *pcBuf, const char* cpszChars, + int nLen, unsigned char cStop, boolean bTestEqual) +{ + int n; + unsigned a[8]; + + // Initialize bit mask based on the input flag that specifies whether + // we are looking for a character that matches "any" or "none" + // of the characters in the search string + + #define ENTRY(c) a[((c)&7)] // c's bit lives here + #define SHIFT(c) ((c)>>3) // c's bit is shifted by this much + + if (bTestEqual) { + std_memset(a, 0, STD_SIZEOF(a)); + do { + ENTRY(cStop) |= (0x80000000U >> SHIFT(cStop)); + cStop = (unsigned char)*cpszChars++; + } while (cStop); + } + else { + std_memset(a, 0xFF, STD_SIZEOF(a)); + + while (0 != (cStop = (unsigned char)*cpszChars++)) { + ENTRY(cStop) ^= (0x80000000U >> SHIFT(cStop)); + } + } + + + // Search buffer + + pcBuf += nLen; + n = -nLen; + do { + unsigned char uc = (unsigned char)pcBuf[n]; + // testing for negative after shift is quicker than comparison + if ( (int)(ENTRY(uc) << SHIFT(uc)) < 0) { + break; + } + } while (++n); + + return (char*)(pcBuf+n); +} + + +void* std_memchrsend(const void* pBuf, const char* cpszChars, int nLen) +{ + if (nLen <= 0) { + return (void*)pBuf; + } + if ('\0' == *cpszChars) { + return (char*)pBuf + nLen; + } + + return x_scanbytes((const char*)pBuf, cpszChars+1, nLen, + (unsigned char)*cpszChars, TRUE); +} + + +char* std_strchrsend(const char* cpszSrch, const char* cpszChars) +{ + return x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE); +} + + +char *std_strchrs(const char* cpszSrch, const char* cpszChars) +{ + const char *pc = std_strchrsend(cpszSrch, cpszChars); + + return (*pc ? (char*)pc : 0); +} + + +char* std_striends(const char* cpsz, const char* cpszSuffix) +{ + int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix); + + if ((0 <= nOffset) && + (0 == std_stricmp(cpsz+nOffset, cpszSuffix))) { + + return (char*)(cpsz+nOffset); + } + + return 0; +} + + +char* std_strends(const char* cpsz, const char* cpszSuffix) +{ + int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix); + + if ((0 <= nOffset) && + (0 == std_strcmp(cpsz+nOffset, cpszSuffix))) { + + return (char*)(cpsz + nOffset); + } + + return 0; +} + +char* std_strbegins(const char* cpsz, const char* cpszPrefix) +{ + for (;;) { + if ('\0' == *cpszPrefix) { + return (char*)cpsz; + } + + if (*cpszPrefix != *cpsz) { + return 0; + } + + ++cpszPrefix; + ++cpsz; + } + // not reached +} + +char* std_stribegins(const char* cpsz, const char* cpszPrefix) +{ + for (;;) { + if ('\0' == *cpszPrefix) { + return (char*)cpsz; + } + + if (x_casecmp((unsigned char)*cpszPrefix, (unsigned char)*cpsz)) { + return 0; + } + + ++cpszPrefix; + ++cpsz; + } + // not reached +} + +int std_strcspn(const char* cpszSrch, const char* cpszChars) +{ + const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE); + + return (pc - cpszSrch); +} + +int std_strspn(const char* cpszSrch, const char* cpszChars) +{ + const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', FALSE); + + return (pc - cpszSrch); +} + +int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen) +{ + if (nLen > 0) { + int i; + + s1 += nLen; + s2 += nLen; + i = -nLen; + do { + AECHAR c1 = s1[i]; + AECHAR c2 = s2[i]; + int diff = c1 - c2; + + if (diff) { + return diff; + } + + if ('\0' == c1) { + break; + } + } while (++i); + } + + return 0; +} + +int std_wstrcmp(const AECHAR* s1, const AECHAR* s2) +{ + return std_wstrncmp(s1, s2, MAX_INT32); +} + +AECHAR* std_wstrchr(const AECHAR* cpwszText, AECHAR ch) +{ + for (; ; cpwszText++) { + AECHAR chn = *cpwszText; + + if (chn == ch) { + return (AECHAR *)cpwszText; + } + else if ( chn == (AECHAR)0 ) { + return 0; + } + } +} + +AECHAR* std_wstrrchr(const AECHAR* cpwszText, AECHAR ch) +{ + const AECHAR* p = 0; + + do { + if (*cpwszText == ch) { + p = cpwszText; + } + } while (*cpwszText++ != (AECHAR)0); + + return (AECHAR*)p; +} diff --git a/src/std_SwapBytes.c b/src/std_SwapBytes.c new file mode 100644 index 0000000..7caf5db --- /dev/null +++ b/src/std_SwapBytes.c @@ -0,0 +1,194 @@ +/* + * 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 "AEEstd.h" +#include "AEEsmath.h" + + + +static int xMinSize(int a, int b) +{ + if (b < a) { + a = b; + } + return (a >= 0 ? a : 0); +} + + +static void xMoveBytes(byte *pbDest, const byte *pbSrc, int cb) +{ + if (pbDest != pbSrc) { + (void) std_memmove(pbDest, pbSrc, cb); + } +} + + +#ifdef AEE_BIGENDIAN +# define STD_COPY std_CopyBE +# define STD_COPY_SWAP std_CopyLE +#else +# define STD_COPY std_CopyLE +# define STD_COPY_SWAP std_CopyBE +#endif + + +// See std_CopyLE/BE for documentation. This function implements the case +// where host ordering != target byte ordering. +// +int STD_COPY_SWAP(void * pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + byte* pbDest = (byte*)pvDest; + byte* pbSrc = (byte*)pvSrc; + int cbCopied = xMinSize(nDestSize, nSrcSize); + const char * pszNextField; + int cb, nSize; + + nSize = 0; // avoid warning when using RVCT2.2 with -O1 + + pszNextField = pszFields; + + for (cb = cbCopied; cb > 0; cb -= nSize) { + char ch; + + ch = *pszNextField++; + if ('\0' == ch) { + ch = *pszFields; + pszNextField = pszFields+1; + } + + if (ch == 'S') { + + // S = 2 bytes + + nSize = 2; + if (cb < nSize) { + break; + } else { + byte by = pbSrc[0]; + pbDest[0] = pbSrc[1]; + pbDest[1] = by; + } + } else if (ch == 'L') { + + // L = 4 bytes + + nSize = 4; + if (cb < nSize) { + break; + } else { + byte by = pbSrc[0]; + pbDest[0] = pbSrc[3]; + pbDest[3] = by; + by = pbSrc[1]; + pbDest[1] = pbSrc[2]; + pbDest[2] = by; + } + } else if (ch == 'Q') { + + // Q = 8 bytes + + nSize = 8; + if (cb < nSize) { + break; + } else { + byte by = pbSrc[0]; + pbDest[0] = pbSrc[7]; + pbDest[7] = by; + by = pbSrc[1]; + pbDest[1] = pbSrc[6]; + pbDest[6] = by; + by = pbSrc[2]; + pbDest[2] = pbSrc[5]; + pbDest[5] = by; + by = pbSrc[3]; + pbDest[3] = pbSrc[4]; + pbDest[4] = by; + } + } else { + + // None of the above => read decimal and copy without swap + + if (ch >= '0' && ch <= '9') { + nSize = (int) (ch - '0'); + while ( (ch = *pszNextField) >= '0' && ch <= '9') { + nSize = nSize*10 + (int)(ch - '0'); + ++pszNextField; + } + // Check bounds & ensure progress + if (nSize > cb || nSize <= 0) { + nSize = cb; + } + } else { + // Unexpected character: copy rest of data + nSize = cb; + } + + xMoveBytes(pbDest, pbSrc, nSize); + } + + pbDest += nSize; + pbSrc += nSize; + } + + if (cb > 0) { + + // Swap could not be completed: 0 < cb < nSize <= 8 + + byte byBuf[8]; + + // If entire value is available in source, use swapped version + if (nSrcSize - (pbSrc - (byte*)pvSrc) >= nSize) { + int i; + for (i=0; i<cb; ++i) { + byBuf[i] = pbSrc[nSize-1-i]; + } + pbSrc = byBuf; + } + std_memmove(pbDest, pbSrc, cb); + } + + return cbCopied; +} + + +// See std_CopyLE/BE for documentation. This function implements the case +// where host ordering == target byte ordering. +// +int STD_COPY(void *pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + int cb = xMinSize(nDestSize, nSrcSize); + (void)pszFields; + xMoveBytes(pvDest, pvSrc, cb); + return cb; +} + + diff --git a/src/std_dtoa.c b/src/std_dtoa.c new file mode 100644 index 0000000..943be3b --- /dev/null +++ b/src/std_dtoa.c @@ -0,0 +1,504 @@ +/* + * 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 "AEEStdDef.h" +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "std_dtoa.h" +#include "math.h" + +// +// Useful Macros +// +#define FAILED(b) ( (b) != AEE_SUCCESS ? TRUE : FALSE ) +#define CLEANUP_ON_ERROR(b,l) if( FAILED( b ) ) { goto l; } +#define FP_POW_10(n) fp_pow_10(n) + +static __inline +uint32 std_dtoa_clz32( uint32 ulVal ) +// +// This function returns the number of leading zeroes in a uint32. +// This is a naive implementation that uses binary search. This could be +// replaced by an optimized inline assembly code. +// +{ + if( (int)ulVal <= 0 ) + { + return ( ulVal == 0 ) ? 32 : 0; + } + else + { + uint32 uRet = 28; + uint32 uTmp = 0; + uTmp = ( ulVal > 0xFFFF ) * 16; ulVal >>= uTmp, uRet -= uTmp; + uTmp = ( ulVal > 0xFF ) * 8; ulVal >>= uTmp, uRet -= uTmp; + uTmp = ( ulVal > 0xF ) * 4; ulVal >>= uTmp, uRet -= uTmp; + return uRet + ( ( 0x55AF >> ( ulVal * 2 ) ) & 3 ); + } +} + +static __inline +uint32 std_dtoa_clz64( uint64 ulVal ) +// +// This function returns the number of leading zeroes in a uint64. +// +{ + uint32 ulCount = 0; + + if( !( ulVal >> 32 ) ) + { + ulCount += 32; + } + else + { + ulVal >>= 32; + } + + return ulCount + std_dtoa_clz32( (uint32)ulVal ); +} + +double fp_pow_10( int nPow ) +{ + double dRet = 1.0; + int nI = 0; + boolean bNegative = FALSE; + double aTablePos[] = { 0, 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, 1e64, 1e128, + 1e256 }; + double aTableNeg[] = { 0, 1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32, 1e-64, 1e-128, + 1e-256 }; + double* pTable = aTablePos; + int nTableSize = STD_ARRAY_SIZE( aTablePos ); + + if( 0 == nPow ) + { + return 1.0; + } + + if( nPow < 0 ) + { + bNegative = TRUE; + nPow = -nPow; + pTable = aTableNeg; + nTableSize = STD_ARRAY_SIZE( aTableNeg ); + } + + for( nI = 1; nPow && (nI < nTableSize); nI++ ) + { + if( nPow & 1 ) + { + dRet *= pTable[nI]; + } + + nPow >>= 1; + } + + if( nPow ) + { + // Overflow. Trying to compute a large power value. + uint64 ulInf = STD_DTOA_FP_POSITIVE_INF; + dRet = bNegative ? 0 : UINT64_TO_DOUBLE( ulInf ); + } + + return dRet; +} + +double fp_round( double dNumber, int nPrecision ) +// +// This functions rounds dNumber to the specified precision nPrecision. +// For example: +// fp_round(2.34553, 3) = 2.346 +// fp_round(2.34553, 4) = 2.3455 +// +{ + double dResult = dNumber; + double dRoundingFactor = FP_POW_10( -nPrecision ) * 0.5; + + if( dNumber < 0 ) + { + dResult = dNumber - dRoundingFactor; + } + else + { + dResult = dNumber + dRoundingFactor; + } + + return dResult; +} + +int fp_log_10( double dNumber ) +// +// This function finds the integer part of the log_10( dNumber ). +// The function assumes that dNumber != 0. +// +{ + // Absorb the negative sign + if( dNumber < 0 ) + { + dNumber = -dNumber; + } + + return (int)( floor( log10( dNumber ) ) ); +} + +int fp_check_special_cases( double dNumber, FloatingPointType* pNumberType ) +// +// This function evaluates the input floating-point number dNumber to check for +// following special cases: NaN, +/-Infinity. +// The evaluation is based on the IEEE Standard 754 for Floating Point Numbers +// +{ + int nError = AEE_SUCCESS; + FloatingPointType NumberType = FP_TYPE_UNKOWN; + uint64 ullValue = 0; + uint64 ullSign = 0; + int64 n64Exponent = 0; + uint64 ullMantissa = 0; + + ullValue = DOUBLE_TO_UINT64( dNumber ); + + // Extract the sign, exponent and mantissa + ullSign = FP_SIGN( ullValue ); + n64Exponent = FP_EXPONENT_BIASED( ullValue ); + ullMantissa = FP_MANTISSA_DENORM( ullValue ); + + // + // Rules for special cases are listed below: + // For Infinity, the following needs to be true: + // 1. Exponent should have all bits set to 1. + // 2. Mantissa should have all bits set to 0. + // + // For NaN, the following needs to be true: + // 1. Exponent should have all bits set to 1. + // 2. Mantissa should be non-zero. + // Note that we do not differentiate between QNaNs and SNaNs. + // + if( STD_DTOA_DP_INFINITY_EXPONENT_ID == n64Exponent ) + { + if( 0 == ullMantissa ) + { + // Inifinity. + if( ullSign ) + { + NumberType = FP_TYPE_NEGATIVE_INF; + } + else + { + NumberType = FP_TYPE_POSITIVE_INF; + } + } + else + { + // NaN + NumberType = FP_TYPE_NAN; + } + } + else + { + // A normal number + NumberType = FP_TYPE_GENERAL; + } + + // Set the output value + *pNumberType = NumberType; + + return nError; +} + +int std_dtoa_decimal( double dNumber, int nPrecision, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ] ) +{ + int nError = AEE_SUCCESS; + boolean bNegativeNumber = FALSE; + double dIntegerPart = 0.0; + double dFractionPart = 0.0; + double dTempIp = 0.0; + double dTempFp = 0.0; + int nMaxIntDigs = STD_DTOA_FORMAT_INTEGER_SIZE; + uint32 ulI = 0; + int nIntStartPos = 0; + + // Optimization: Special case an input of 0 + if( 0.0 == dNumber ) + { + acIntegerPart[0] = '0'; + acIntegerPart[1] = '\0'; + + for( ulI = 0; (ulI < STD_DTOA_FORMAT_FRACTION_SIZE - 1) && (nPrecision > 0); + ulI++, nPrecision-- ) + { + acFractionPart[ulI] = '0'; + } + acFractionPart[ ulI ] = '\0'; + + goto bail; + } + + // Absorb the negative sign + if( dNumber < 0 ) + { + acIntegerPart[0] = '-'; + nIntStartPos = 1; + dNumber = -dNumber; + bNegativeNumber = TRUE; + } + + // Split the input number into it's integer and fraction parts + dFractionPart = modf( dNumber, &dIntegerPart ); + + // First up, convert the integer part + if( 0.0 == dIntegerPart ) + { + acIntegerPart[ nIntStartPos ] = '0'; + } + else + { + double dRoundingConst = FP_POW_10( -STD_DTOA_PRECISION_ROUNDING_VALUE ); + int nIntDigs = 0; + int nI = 0; + + // Compute the number of digits in the integer part of the number + nIntDigs = fp_log_10( dIntegerPart ) + 1; + + // For negative numbers, a '-' sign has already been written. + if( TRUE == bNegativeNumber ) + { + nIntDigs++; + } + + // Check for overflow + if( nIntDigs >= nMaxIntDigs ) + { + // Overflow! + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + + // Null Terminate the string + acIntegerPart[ nIntDigs ] = '\0'; + + for( nI = nIntDigs - 1; nI >= nIntStartPos; nI-- ) + { + dIntegerPart = dIntegerPart / 10.0; + dTempFp = modf( dIntegerPart, &dTempIp ); + + // Round it to the a specific precision + dTempFp = dTempFp + dRoundingConst; + + // Convert the digit to a character + acIntegerPart[ nI ] = (int)( dTempFp * 10 ) + '0'; + if( !MY_ISDIGIT( acIntegerPart[ nI ] ) ) + { + // Overflow! + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + dIntegerPart = dTempIp; + } + } + + // Just a double check for integrity sake. This should ideally never happen. + // Out of bounds scenario. That is, the integer part of the input number is + // too large. + if( dIntegerPart != 0.0 ) + { + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + + // Now, convert the fraction part + for( ulI = 0; ( nPrecision > 0 ) && ( ulI < STD_DTOA_FORMAT_FRACTION_SIZE - 1 ); + nPrecision--, ulI++ ) + { + if( 0.0 == dFractionPart ) + { + acFractionPart[ ulI ] = '0'; + } + else + { + double dRoundingValue = FP_POW_10( -( nPrecision + + STD_DTOA_PRECISION_ROUNDING_VALUE ) ); + acFractionPart[ ulI ] = (int)( ( dFractionPart + dRoundingValue ) * 10.0 ) + '0'; + if( !MY_ISDIGIT( acFractionPart[ ulI ] ) ) + { + // Overflow! + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + + dFractionPart = ( dFractionPart * 10.0 ) - + (int)( ( dFractionPart + FP_POW_10( -nPrecision - 6 ) ) * 10.0 ); + } + } + + +bail: + + return nError; +} + +int std_dtoa_hex( double dNumber, int nPrecision, char cFormat, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ], + int* pnExponent ) +{ + int nError = AEE_SUCCESS; + uint64 ullMantissa = 0; + uint64 ullSign = 0; + int64 n64Exponent = 0; + static const char HexDigitsU[] = "0123456789ABCDEF"; + static const char HexDigitsL[] = "0123456789abcde"; + boolean bFirstDigit = TRUE; + int nI = 0; + int nF = 0; + uint64 ullValue = DOUBLE_TO_UINT64( dNumber ); + int nManShift = 0; + const char *pcDigitArray = ( cFormat == 'A' ) ? HexDigitsU : HexDigitsL; + boolean bPrecisionSpecified = TRUE; + + // If no precision is specified, then set the precision to be fairly + // large. + if( nPrecision < 0 ) + { + nPrecision = STD_DTOA_FORMAT_FRACTION_SIZE; + bPrecisionSpecified = FALSE; + } + else + { + bPrecisionSpecified = TRUE; + } + + // Extract the sign, exponent and mantissa + ullSign = FP_SIGN( ullValue ); + n64Exponent = FP_EXPONENT( ullValue ); + ullMantissa = FP_MANTISSA( ullValue ); + + // Write out the sign + if( ullSign ) + { + acIntegerPart[ nI++ ] = '-'; + } + + // Optimization: Special case an input of 0 + if( 0.0 == dNumber ) + { + acIntegerPart[0] = '0'; + acIntegerPart[1] = '\0'; + + for( nF = 0; (nF < STD_DTOA_FORMAT_FRACTION_SIZE - 1) && (nPrecision > 0); + nF++, nPrecision-- ) + { + acFractionPart[nF] = '0'; + } + acFractionPart[nF] = '\0'; + + goto bail; + } + + // The mantissa is in lower 53 bits (52 bits + an implicit 1). + // If we are dealing with a denormalized number, then the implicit 1 + // is absent. The above macros would have then set that bit to 0. + // Shift the mantisaa on to the highest bits. + + if( 0 == ( n64Exponent + STD_DTOA_DP_EXPONENT_BIAS ) ) + { + // DENORMALIZED NUMBER. + // A denormalized number is of the form: + // 0.bbb...bbb x 2^Exponent + // Shift the mantissa to the higher bits while discarding the leading 0 + ullMantissa <<= 12; + + // Lets update the exponent so as to make sure that the first hex value + // in the mantissa is non-zero, i.e., at least one of the first 4 bits is + // non-zero. + nManShift = std_dtoa_clz64( ullMantissa ) - 3; + if( nManShift > 0 ) + { + ullMantissa <<= nManShift; + n64Exponent -= nManShift; + } + } + else + { + // NORMALIZED NUMBER. + // A normalized number has the following form: + // 1.bbb...bbb x 2^Exponent + // Shift the mantissa to the higher bits while retaining the leading 1 + ullMantissa <<= 11; + } + + // Now, lets get the decimal point out of the picture by shifting the + // exponent by 1. + n64Exponent++; + + // Read the mantissa four bits at a time to form the hex output + for( nI = 0, nF = 0, bFirstDigit = TRUE; ullMantissa != 0; + ullMantissa <<= 4 ) + { + uint64 ulHexVal = ullMantissa & 0xF000000000000000uLL; + ulHexVal >>= 60; + if( bFirstDigit ) + { + // Write to the integral part of the number + acIntegerPart[ nI++ ] = pcDigitArray[ulHexVal]; + bFirstDigit = FALSE; + } + else if( nF < nPrecision ) + { + // Write to the fractional part of the number + acFractionPart[ nF++ ] = pcDigitArray[ulHexVal]; + } + } + + // Pad the fraction with trailing zeroes upto the specified precision + for( ; bPrecisionSpecified && (nF < nPrecision); nF++ ) + { + acFractionPart[ nF ] = '0'; + } + + // Now the output is of the form; + // h.hhh x 2^Exponent + // where h is a non-zero hexadecimal number. + // But we were dealing with a binary fraction 0.bbb...bbb x 2^Exponent. + // Therefore, we need to subtract 4 from the exponent (since the shift + // was to the base 16 and the exponent is to the base 2). + n64Exponent -= 4; + *pnExponent = (int)n64Exponent; + +bail: + return nError; +} diff --git a/src/std_dtoa.h b/src/std_dtoa.h new file mode 100644 index 0000000..cea00c4 --- /dev/null +++ b/src/std_dtoa.h @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#ifndef STD_DTOA_H +#define STD_DTOA_H + +// +// Constant Definitions +// + +// For floating point numbers, the range of a double precision number is +// approximately +/- 10 ^ 308.25 as per the IEEE Standard 754. +// As such, the maximum size of the integer portion of the +// string is assumed to be 311 (309 + sign + \0). The maximum +// size of the fractional part is assumed to be 100. Thus, the +// maximum size of the string that would contain the number +// after conversion is safely assumed to be 420 (including any +// prefix, the null character and exponent specifiers 'e'). +// +// The buffers that contain the converted integer and the fraction parts of +// the float are safely assumed to be of size 310. +#define STD_DTOA_FORMAT_FLOAT_SIZE 420 +#define STD_DTOA_FORMAT_INTEGER_SIZE 311 +#define STD_DTOA_FORMAT_FRACTION_SIZE 100 + +// Constants for operations on the IEEE 754 representation of double +// precision floating point numbers. +#define STD_DTOA_DP_SIGN_SHIFT_COUNT 63 +#define STD_DTOA_DP_EXPONENT_SHIFT_COUNT 52 +#define STD_DTOA_DP_EXPONENT_MASK 0x7ff +#define STD_DTOA_DP_EXPONENT_BIAS 1023 +#define STD_DTOA_DP_MANTISSA_MASK ( ( (uint64)1 << 52 ) - 1 ) +#define STD_DTOA_DP_INFINITY_EXPONENT_ID 0x7FF +#define STD_DTOA_DP_MAX_EXPONENT 1023 +#define STD_DTOA_DP_MIN_EXPONENT_NORM -1022 +#define STD_DTOA_DP_MIN_EXPONENT_DENORM -1074 +#define STD_DTOA_DP_MAX_EXPONENT_DEC 308 +#define STD_DTOA_DP_MIN_EXPONENT_DEC_DENORM -323 + +#define STD_DTOA_PRECISION_ROUNDING_VALUE 4 +#define STD_DTOA_DEFAULT_FLOAT_PRECISION 6 + +#define STD_DTOA_NEGATIVE_INF_UPPER_CASE "-INF" +#define STD_DTOA_NEGATIVE_INF_LOWER_CASE "-inf" +#define STD_DTOA_POSITIVE_INF_UPPER_CASE "INF" +#define STD_DTOA_POSITIVE_INF_LOWER_CASE "inf" +#define STD_DTOA_NAN_UPPER_CASE "NAN" +#define STD_DTOA_NAN_LOWER_CASE "nan" +#define STD_DTOA_FP_POSITIVE_INF 0x7FF0000000000000uLL +#define STD_DTOA_FP_NEGATIVE_INF 0xFFF0000000000000uLL +#define STD_DTOA_FP_SNAN 0xFFF0000000000001uLL +#define STD_DTOA_FP_QNAN 0xFFFFFFFFFFFFFFFFuLL + +// +// Useful Macros +// + +#define MY_ISDIGIT(c) ( ( (c) >= '0' ) && ( (c) <= '9' ) ) +#define FP_EXPONENT(u) ( ( ( (u) >> STD_DTOA_DP_EXPONENT_SHIFT_COUNT ) \ + & STD_DTOA_DP_EXPONENT_MASK ) - STD_DTOA_DP_EXPONENT_BIAS ) +#define FP_EXPONENT_BIASED(u) ( ( (u) >> STD_DTOA_DP_EXPONENT_SHIFT_COUNT ) \ + & STD_DTOA_DP_EXPONENT_MASK ) +#define FP_MANTISSA_NORM(u) ( ( (u) & STD_DTOA_DP_MANTISSA_MASK ) | \ + ( (uint64)1 << STD_DTOA_DP_EXPONENT_SHIFT_COUNT ) ) +#define FP_MANTISSA_DENORM(u) ( (u) & STD_DTOA_DP_MANTISSA_MASK ) +#define FP_MANTISSA(u) ( FP_EXPONENT_BIASED(u) ? FP_MANTISSA_NORM(u) : \ + FP_MANTISSA_DENORM(u) ) +#define FP_SIGN(u) ( (u) >> STD_DTOA_DP_SIGN_SHIFT_COUNT ) +#define DOUBLE_TO_UINT64(d) ( *( (uint64*) &(d) ) ) +#define DOUBLE_TO_INT64(d) ( *( (int64*) &(d) ) ) +#define UINT64_TO_DOUBLE(u) ( *( (double*) &(u) ) ) + +// +// Type Definitions +// + +typedef enum +{ + FP_TYPE_UNKOWN = 0, + FP_TYPE_NEGATIVE_INF, + FP_TYPE_POSITIVE_INF, + FP_TYPE_NAN, + FP_TYPE_GENERAL, +} FloatingPointType; + +// +// Function Declarations +// + +#ifdef __cplusplus +extern "C" { +#endif // #ifdef __cplusplus + +double fp_pow_10( int nPow ); +double fp_round( double dNumber, int nPrecision ); +int fp_log_10( double dNumber ); +int fp_check_special_cases( double dNumber, FloatingPointType* pNumberType ); +int std_dtoa_decimal( double dNumber, int nPrecision, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ] ); +int std_dtoa_hex( double dNumber, int nPrecision, char cFormat, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ], + int* pnExponent ); + +#ifdef __cplusplus +} +#endif // #ifdef __cplusplus + +#endif // STD_DTOA_H + diff --git a/src/std_mem.c b/src/std_mem.c new file mode 100644 index 0000000..abe45ed --- /dev/null +++ b/src/std_mem.c @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/* +======================================================================= + +FILE: std_mem.c + +SERVICES: apiOne std lib memory operations stuff + +*/ + +#include <string.h> +#include "AEEstd.h" +#include "AEEStdErr.h" + +#if defined __hexagon__ +#include "stringl/stringl.h" + +//Add a weak reference so shared objects work with older images +#pragma weak memscpy +#pragma weak memsmove +#endif /*__hexagon__*/ + +void* std_memset(void* p, int c, int nLen) +{ + if (nLen < 0) { + return p; + } + return memset(p, c, (size_t)nLen); +} + +void* std_memmove(void* pTo, const void* cpFrom, int nLen) +{ + if (nLen <= 0) { + return pTo; + } +#ifdef __hexagon__ + std_memsmove(pTo, (size_t)nLen, cpFrom, (size_t)nLen); + return pTo; +#else + return memmove(pTo, cpFrom, (size_t)nLen); +#endif +} + +int std_memscpy(void *dst, int dst_size, const void *src, int src_size){ + size_t copy_size = 0; + + if(dst_size <0 || src_size <0){ + return AEE_EBADSIZE; + } + +#if defined (__hexagon__) + if (memscpy){ + return memscpy(dst,dst_size,src,src_size); + } +#endif + + copy_size = (dst_size <= src_size)? dst_size : src_size; + memcpy(dst, src, copy_size); + return copy_size; +} + +int std_memsmove(void *dst, int dst_size, const void *src, int src_size){ + size_t copy_size = 0; + + if(dst_size <0 || src_size <0){ + return AEE_EBADSIZE; + } + +#if defined (__hexagon__) + if (memsmove){ + return memsmove(dst,dst_size,src,src_size); + } +#endif + + copy_size = (dst_size <= src_size)? dst_size : src_size; + memmove(dst, src, copy_size); + return copy_size; +} + diff --git a/src/std_path.c b/src/std_path.c new file mode 100644 index 0000000..b8e1d3f --- /dev/null +++ b/src/std_path.c @@ -0,0 +1,165 @@ +/* + * 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. + */ + +/* +======================================================================= + +FILE: std_path.c + +======================================================================= +======================================================================= +*/ + +#include "AEEstd.h" +#include "AEEBufBound.h" +#include <string.h> +/*=========================================================================== + +===========================================================================*/ +int std_makepath(const char* cpszDir, const char* cpszFile, + char* pszOut, int nOutLen) +{ + BufBound bb; + + BufBound_Init(&bb, pszOut, nOutLen); + + BufBound_Puts(&bb, cpszDir); + + if (('\0' != cpszDir[0]) && /* non-empty dir */ + ('/' != cpszDir[std_strlen(cpszDir)-1])) { /* no slash at end of dir */ + BufBound_Putc(&bb, '/'); + } + if ('/' == cpszFile[0]) { + cpszFile++; + } + + BufBound_Puts(&bb, cpszFile); + + BufBound_ForceNullTerm(&bb); + + return BufBound_Wrote(&bb) - 1; + +} + +/*=========================================================================== + +===========================================================================*/ +char* std_splitpath(const char* cpszPath, const char* cpszDir) +{ + const char* cpsz = cpszPath; + + while ( ! ('\0' == cpszDir[0] || + ('/' == cpszDir[0] && '\0' == cpszDir[1])) ){ + + if (*cpszDir != *cpsz) { + return 0; + } + + ++cpsz; + ++cpszDir; + } + + /* Found the filename part of the path. + It should begin with a '/' unless there is no filename */ + if ('/' == *cpsz) { + cpsz++; + } + else if ('\0' != *cpsz) { + cpsz = 0; + } + + return (char*)cpsz; +} + +char* std_cleanpath(char* pszPath) +{ + char* pszStart = pszPath; + char* pc; + char* pcEnd = pszStart+std_strlen(pszStart); + + /* preserve leading slash */ + if ('/' == pszStart[0]) { + pszStart++; + } + + pc = pszStart; + + while ((char*)0 != (pc = std_strstr(pc, "/."))) { + char* pcDelFrom; + + if ('/' == pc[2] || '\0' == pc[2]) { + /* delete "/." */ + pcDelFrom = pc; + pc += 2; + } else if ('.' == pc[2] && ('/' == pc[3] || '\0' == pc[3])) { + /* delete "/element/.." */ + pcDelFrom = std_memrchrbegin(pszStart, '/', pc - pszStart); + pc += 3; + } else { + pc += 2; + continue; + } + + std_memmove(pcDelFrom, pc, pcEnd-pcDelFrom); + + pc = pcDelFrom; + } + + /* eliminate leading "../" */ + while (pszStart == std_strstr(pszStart, "../")) { + std_memmove(pszStart, pszStart+2, pcEnd-pszStart); + } + + /* eliminate leading "./" */ + while (pszStart == std_strstr(pszStart, "./")) { + std_memmove(pszStart, pszStart+1, pcEnd-pszStart); + } + + if (!strncmp(pszStart,"..",2) || !strncmp(pszStart,".",1)) { + pszStart[0] = '\0'; + } + + /* whack double '/' */ + while ((char*)0 != (pc = std_strstr(pszPath, "//"))) { + std_memmove(pc, pc+1, pcEnd-pc); + } + + return pszPath; +} + +char* std_basename(const char* cpszFile) +{ + const char* cpsz; + + if ((char*)0 != (cpsz = std_strrchr(cpszFile,'/'))) { + cpszFile = cpsz+1; + } + + return (char*)cpszFile; +} diff --git a/src/std_strlprintf.c b/src/std_strlprintf.c new file mode 100644 index 0000000..c927dc8 --- /dev/null +++ b/src/std_strlprintf.c @@ -0,0 +1,759 @@ +/* + * 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 "AEEstd.h" +#include "AEEBufBound.h" +#include "AEEsmath.h" +#include "AEEStdErr.h" +#include "std_dtoa.h" +//#include "math.h" + +//============================================================================== +// Macro definitions +//============================================================================== + +#define ISDIGIT(c) ( (c) >= '0' && (c) <= '9') +#define TOLOWER(c) ( (c) | 32 ) // works only for letters +#define FAILED(b) ( (b) != AEE_SUCCESS ? TRUE : FALSE ) +#define CLEANUP_ON_ERROR(b,l) if( FAILED( b ) ) { goto l; } +#define ROUND(d, p) fp_round( d, p ) +#define FP_POW_10(n) fp_pow_10(n) + +//============================================================================== +// Type definitions +//============================================================================== + + +// Formatting flags + +#define FF_PLUS 1 // '+' +#define FF_MINUS 2 // '-' +#define FF_POUND 4 // '#' +#define FF_BLANK 8 // ' ' +#define FF_ZERO 16 // '0' + +typedef struct { + + // Parsed values (from "%..." expression) + + int flags; // FF_PLUS, FF_MINUS, etc. + char cType; // d, s, c, x, X, etc. + int32 nWidth; // number preceding '.' : controls padding + int32 nPrecision; // number following '.' (-1 if not given) + + // Computed values + + const char * pszStr; // string holding prefix + value + int nPrefix; // # of numeric prefix bytes in pszStr[] + int nLen; // length of string (after prefix) + int nNumWidth; // minimum numeric value size (pad with '0') + +} FieldFormat; + +typedef int (*pfnFormatFloat)(FieldFormat* me, double dNumber, char* pcBuffer); + +//============================================================================== +// Function definitions +//============================================================================== + +// Read an unsigned decimal integer +// +static int ScanDecimal(const char **ppsz) +{ + int n = 0; + const char *psz; + + for (psz = *ppsz; ISDIGIT(*psz); ++psz) { + n = n*10 + (int) (*psz - '0'); + } + *ppsz = psz; + return n; +} + + +#define FORMATNUMBER_SIZE 24 // octal: 22 + '0' + null ; decimal: 20 + sign + null + + +// Convert number to string, setting computed fields in FieldFormat. +// +// pcBuf[] must have room for at least FORMATNUMBER_SIZE characters +// return value: length of string. +// +static __inline void +FormatNumber(FieldFormat *me, char pcBuf[FORMATNUMBER_SIZE], uint64 uNum64) +{ + char cType = me->cType; + const char *cpszDigits; + char *pc = pcBuf; + int nBase; + char *pcRev; + + if (cType == 'p') { + cType = 'X'; + me->nPrecision = 8; + } + + if (me->nPrecision >= 0) { + me->nNumWidth = me->nPrecision; + // Odd thing: '0' flag is ignored for numbers when precision is + // specified. + me->flags &= ~FF_ZERO; + } else { + me->nNumWidth = 1; + } + + // Output prefix + + if (( 'd' == cType || 'i' == cType)) { + if ((int64)uNum64 < 0) { + *pc++ = '-'; + uNum64 = (uint64)-(int64)uNum64; + } else if (me->flags & FF_PLUS) { + *pc++ = '+'; + } else if (me->flags & FF_BLANK) { + *pc++ = ' '; + } + } + + if ((me->flags & FF_POUND) && 0 != uNum64) { + if ('x' == TOLOWER(cType)) { + *pc++ = '0'; + *pc++ = cType; + } else if ('o' == cType) { + *pc++ = '0'; + // Odd thing about libc printf: "0" prefix counts as part of minimum + // width, but "0x" prefix does not. + --me->nNumWidth; + } + } + me->nPrefix = pc - pcBuf; + + // Output unsigned numeric value + + nBase = ('o' == cType ? 8 : + 'x' == TOLOWER(cType) ? 16 : + 10); + cpszDigits = ((cType == 'X') ? "0123456789ABCDEF" + : "0123456789abcdef"); + + pcRev = pc; + + while (uNum64) { + *pc++ = cpszDigits[uNum64 % (unsigned)nBase]; + uNum64 /= (unsigned)nBase; + } + + *pc = '\0'; + + me->pszStr = pcBuf; + me->nLen = pc - pcRev; + + // Reverse string + + --pc; + for (; pcRev < pc; ++pcRev, --pc) { + char c = *pc; + *pc = *pcRev; + *pcRev = c; + } +} + +// +// This function converts the input floating point number dNumber to an +// ASCII string using either %f or %F formatting. This functions assumes +// that dNumer is a valid floating point number (i.e., dNumber is NOT +// +/-INF or NaN). The size of the output buffer pcBuffer should be at +// least STD_DTOA_FORMAT_FLOAT_SIZE. +// +static int ConvertFloat(FieldFormat* me, double dNumber, char* pcBuffer, + int nBufSize) +{ + int nError = AEE_SUCCESS; + int32 nPrecision = 0; + int nIndex = 0; + BufBound OutBuf; + char szIntegerPart[STD_DTOA_FORMAT_INTEGER_SIZE] = {0}; + char szFractionPart[STD_DTOA_FORMAT_FRACTION_SIZE] = {0}; + int nExponent = 0; + char cType = TOLOWER(me->cType); + + // Set the precision for conversion + nPrecision = me->nPrecision; + if (nPrecision < 0) { + // No precision was specified, set it to the default value if the + // format specifier is not %a + if (cType != 'a') { + nPrecision = STD_DTOA_DEFAULT_FLOAT_PRECISION; + } + } + else if ((0 == nPrecision) && ('g' == cType)) { + nPrecision = 1; + } + + if (cType != 'a') { + // For %g, check whether to use %e of %f formatting style. + // Also, set the precision value accordingly since in this case the user + // specified value is really the number of significant digits. + // These next few steps should be skipped if the input number is 0. + if (dNumber != 0.0) { + nExponent = fp_log_10(dNumber); + if ('g' == cType) { + if ((nExponent < -4) || (nExponent >= nPrecision)) { + cType = 'e'; + nPrecision = nPrecision - 1; + } + else { + cType = 'f'; + nPrecision = nPrecision - nExponent - 1; + } + } + + // For %e, convert the number to the form d.ddd + if ('e' == cType) { + dNumber = dNumber / FP_POW_10(nExponent); + } + + // Now, round the number to the specified precision + dNumber = ROUND(dNumber, nPrecision); + + // For %e, the rounding operation may have resulted in a number dd.ddd + // Reconvert it to the form d.ddd + if (('e' == cType) && ((dNumber >= 10.0) || (dNumber <= -10.0))) { + dNumber = dNumber / 10.0; + nExponent++; + } + } + + // Convert the decmial number to string + nError = std_dtoa_decimal(dNumber, nPrecision, szIntegerPart, szFractionPart); + CLEANUP_ON_ERROR(nError, bail); + } + else + { + // Conver the hex floating point number to string + nError = std_dtoa_hex(dNumber, nPrecision, me->cType, szIntegerPart, + szFractionPart, &nExponent); + CLEANUP_ON_ERROR(nError, bail); + } + + + // + // Write the output as per the specified format. + // First: Check for any prefixes that need to be added to the output. + // The only possible prefixes are '-', '+' or ' '. The following rules + // are applicable: + // 1. One and only one prefix will be applicable at any time. + // 2. If the number is negative, then '+' and ' ' are not applicable. + // 3. For positive numbers, the prefix '+' takes precedence over ' '. + // + // In addition, we were dealing with a hex floating point number (%a), + // then we need to write of the 0x prefix. + // + BufBound_Init(&OutBuf, pcBuffer, nBufSize); + if (dNumber < 0.0) { + // The '-' sign would have already been added to the szIntegerPart by + // the conversion function. + me->nPrefix = 1; + } + if (dNumber >= 0.0){ + if (me->flags & FF_PLUS) { + BufBound_Putc(&OutBuf, '+'); + me->nPrefix = 1; + } + else if(me->flags & FF_BLANK) { + BufBound_Putc(&OutBuf, ' '); + me->nPrefix = 1; + } + } + + // For %a, write out the 0x prefix + if ('a' == cType) { + BufBound_Putc(&OutBuf, '0'); + BufBound_Putc(&OutBuf, ('a' == me->cType) ? 'x' : 'X'); + me->nPrefix += 2; + } + + // Second: Write the integer part + BufBound_Puts(&OutBuf, szIntegerPart); + + // Third: Write the decimal point followed by the fraction part. + // For %g, we need to truncate the trailing zeros in the fraction. + // Skip this if the '#' flag is specified + if (!(me->flags & FF_POUND) && ('g' == TOLOWER(me->cType))) { + for (nIndex = std_strlen(szFractionPart) - 1; + (nIndex >= 0) && (szFractionPart[nIndex] == '0'); nIndex--) { + szFractionPart[nIndex] = '\0'; + } + } + + // The decimal point is specified only if there are some decimal digits. + // However, if the '#' format specifier is present then the decimal point + // will be present. + if ((me->flags & FF_POUND) || (*szFractionPart != 0)) { + BufBound_Putc(&OutBuf, '.'); + + // Write the fraction part + BufBound_Puts(&OutBuf, szFractionPart); + } + + // For %e and %a, write out the exponent + if (('e' == cType) || ('a' == cType)) { + char* pcExpStart = NULL; + char* pcExpEnd = NULL; + char cTemp = 0; + + if ('a' == me->cType) { + BufBound_Putc(&OutBuf, 'p'); + } + else if ('A' == me->cType) { + BufBound_Putc(&OutBuf, 'P'); + } + else if (('e' == me->cType) || ('g' == me->cType)) { + BufBound_Putc(&OutBuf, 'e'); + } + else { + BufBound_Putc(&OutBuf, 'E'); + } + + // Write the exponent sign + if (nExponent < 0) { + BufBound_Putc(&OutBuf, '-'); + nExponent = -nExponent; + } + else { + BufBound_Putc(&OutBuf, '+'); + } + + // Write out the exponent. + // For %e, the exponent should at least be two digits. + // The exponent to be written will be at most 4 digits as any + // overflow would have been take care of by now. + if (BufBound_Left(&OutBuf) >= 4) { + if ('e' == cType) { + if (nExponent < 10) { + BufBound_Putc(&OutBuf, '0'); + } + } + + pcExpStart = OutBuf.pcWrite; + do { + BufBound_Putc(&OutBuf, '0' + (nExponent % 10)); + nExponent /= 10; + } while (nExponent); + pcExpEnd = OutBuf.pcWrite - 1; + + // Reverse the exponent + for (; pcExpStart < pcExpEnd; pcExpStart++, pcExpEnd--) { + cTemp = *pcExpStart; + *pcExpStart = *pcExpEnd; + *pcExpEnd = cTemp; + } + } + } + + // Null-terminate the string + BufBound_ForceNullTerm(&OutBuf); + + // Set the output parameters + // We do not care if there was enough space in the output buffer or not. + // The output would be truncated to a maximum length of + // STD_DTOA_FORMAT_FLOAT_SIZE. + me->pszStr = OutBuf.pcBuf; + me->nLen = BufBound_ReallyWrote(&OutBuf) - me->nPrefix - 1; + +bail: + + return nError; +} + +// +// This is a wrapper function that converts an input floating point number +// to a string based on a given format specifier %e, %f or %g. It first checks +// if the specified number is a valid floating point number before calling +// the function that does the conversion. +// +// The size of the output buffer pcBuffer should be at least STD_DTOA_FORMAT_FLOAT_SIZE. +// +static int FormatFloat(FieldFormat* me, double dNumber, + char pcBuffer[STD_DTOA_FORMAT_FLOAT_SIZE]) +{ + int nError = AEE_SUCCESS; + FloatingPointType NumberType = FP_TYPE_UNKOWN; + + // Check for error conditions + if (NULL == pcBuffer) { + nError = AEE_EBADPARM; + goto bail; + } + + // Initialize the output params first + me->nLen = 0; + me->nPrefix = 0; + + // Check for special cases such as NaN and Infinity + nError = fp_check_special_cases(dNumber, &NumberType); + CLEANUP_ON_ERROR(nError, bail); + + switch(NumberType) { + case FP_TYPE_NEGATIVE_INF: + + if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NEGATIVE_INF_UPPER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + else { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NEGATIVE_INF_LOWER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + + // Don't pad with 0's + me->flags &= ~FF_ZERO; + + break; + + case FP_TYPE_POSITIVE_INF: + + if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_POSITIVE_INF_UPPER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + else { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_POSITIVE_INF_LOWER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + + // Don't pad with 0's + me->flags &= ~FF_ZERO; + + break; + + case FP_TYPE_NAN: + + if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NAN_UPPER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + else + { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NAN_LOWER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + + // Don't pad with 0's + me->flags &= ~FF_ZERO; + + break; + + case FP_TYPE_GENERAL: + + nError = ConvertFloat(me, dNumber, pcBuffer, + STD_DTOA_FORMAT_FLOAT_SIZE); + CLEANUP_ON_ERROR(nError, bail); + + break; + + default: + + // This should only happen if this function has been modified + // to support other special cases and this block has not been + // updated. + nError = AEE_EFAILED; + goto bail; + } + + // Set the output parameters + me->pszStr = pcBuffer; + + +bail: + + return nError; +} + +static int std_strlprintf_inner(char *pszDest, int nDestSize, + const char *cpszFmt, AEEVaList args, + pfnFormatFloat pfnFormatFloatFunc) +{ + BufBound bb; + const char *pcIn = cpszFmt; + + BufBound_Init(&bb, pszDest, nDestSize); + + for (;;) { + FieldFormat ff; + const char *pcEsc; + char achBuf[FORMATNUMBER_SIZE]; + char achBuf2[STD_DTOA_FORMAT_FLOAT_SIZE]; + char cType; + boolean bLong = 0; + + pcEsc = std_strchrend(pcIn, '%'); + BufBound_Write(&bb, pcIn, pcEsc-pcIn); + + if (0 == *pcEsc) { + break; + } + pcIn = pcEsc+1; + + //---------------------------------------------------- + // Consume "%..." specifiers: + // + // %[FLAGS] [WIDTH] [.PRECISION] [{h | l | I64 | L}] + //---------------------------------------------------- + + std_memset(&ff, 0, sizeof(FieldFormat)); + ff.nPrecision = -1; + + // Consume all flags + for (;;) { + int f; + + f = (('+' == *pcIn) ? FF_PLUS : + ('-' == *pcIn) ? FF_MINUS : + ('#' == *pcIn) ? FF_POUND : + (' ' == *pcIn) ? FF_BLANK : + ('0' == *pcIn) ? FF_ZERO : 0); + + if (0 == f) { + break; + } + + ff.flags |= f; + ++pcIn; + } + + // Consume width + if ('*' == *pcIn) { + AEEVA_ARG(args, ff.nWidth, int32); + pcIn++; + } else { + ff.nWidth = ScanDecimal(&pcIn); + } + if ((ff.flags & FF_MINUS) && ff.nWidth > 0) { + ff.nWidth = -ff.nWidth; + } + + // Consume precision + if ('.' == *pcIn) { + pcIn++; + if ('*' == *pcIn) { // Can be *... (given in int * param) + AEEVA_ARG(args, ff.nPrecision, int32); + pcIn++; + } else { + ff.nPrecision = ScanDecimal(&pcIn); + } + } + + // Consume size designator + { + static const struct { + char szPre[3]; + boolean b64; + } a[] = { + { "l", 0, }, + { "ll", 1, }, + { "L", 1, }, + { "j", 1, }, + { "h", 0, }, + { "hh", 0, }, + { "z", 0 } + }; + + int n = STD_ARRAY_SIZE(a); + + while (--n >= 0) { + const char *psz = std_strbegins(pcIn, a[n].szPre); + if ((const char*)0 != psz) { + pcIn = psz; + bLong = a[n].b64; + break; + } + } + } + + //---------------------------------------------------- + // + // Format output values + // + //---------------------------------------------------- + + ff.cType = cType = *pcIn++; + + if ('s' == cType) { + + // String + char *psz; + + AEEVA_ARG(args, psz, char*); + ff.pszStr = psz; + ff.nLen = std_strlen(psz); + if (ff.nPrecision >= 0 && ff.nPrecision < ff.nLen) { + ff.nLen = ff.nPrecision; + } + + } else if ('c' == cType) { + + // char + AEEVA_ARG(args, achBuf[0], int); + achBuf[1] = '\0'; + ff.pszStr = achBuf; + ff.nLen = 1; + + } else if ('u' == cType || + 'o' == cType || + 'd' == cType || + 'i' == cType || + 'p' == cType || + 'x' == TOLOWER(cType) ) { + + // int + uint64 uArg64; + + if (bLong) { + AEEVA_ARG(args, uArg64, int64); // See how much room needed + } else { + uint32 uArg32; + AEEVA_ARG(args, uArg32, int32); // See how much room needed + uArg64 = uArg32; + if ('d' == cType || 'i' == cType) { + uArg64 = (uint64)(int64)(int32)uArg32; + } + } + + FormatNumber(&ff, achBuf, uArg64); + + } else if (pfnFormatFloatFunc && + ('e' == TOLOWER(cType) || + 'f' == TOLOWER(cType) || + 'g' == TOLOWER(cType) || + 'a' == TOLOWER(cType))) { + + // float + int nError = AEE_SUCCESS; + double dNumber; + + AEEVA_ARG(args, dNumber, double); + nError = pfnFormatFloatFunc(&ff, dNumber, achBuf2); + if (FAILED(nError)) { + continue; + } + + } else if ('\0' == cType) { + + // premature end + break; + + } else { + // Unknown type + BufBound_Putc(&bb, cType); + continue; + } + + // FieldFormat computed variables + nWidth controls output + + if (ff.flags & FF_ZERO) { + ff.nNumWidth = ff.nWidth - ff.nPrefix; + } + + { + int nLen1 = ff.nLen; + int nLen2 = STD_MAX(ff.nNumWidth, nLen1) + ff.nPrefix; + + // Putnc() safely ignores negative sizes + BufBound_Putnc(&bb, ' ', smath_Sub(ff.nWidth,nLen2)); + BufBound_Write(&bb, ff.pszStr, ff.nPrefix); + BufBound_Putnc(&bb, '0', smath_Sub(ff.nNumWidth, nLen1)); + BufBound_Write(&bb, ff.pszStr+ff.nPrefix, nLen1); + BufBound_Putnc(&bb, ' ', smath_Sub(-nLen2, ff.nWidth)); + } + } + + AEEVA_END(args); + + BufBound_ForceNullTerm(&bb); + + /* Return number of bytes required regardless if buffer bound was reached */ + + /* Note that we subtract 1 because the NUL byte which was added in + BufBound_ForceNullTerm() is counted as a written byte; the semantics + of both the ...printf() functions and the strl...() functions call for + the NUL byte to be excluded from the count. */ + + return BufBound_Wrote(&bb)-1; +} + +int std_vstrlprintf(char *pszDest, int nDestSize, + const char *cpszFmt, + AEEVaList args) +{ + return std_strlprintf_inner(pszDest, nDestSize, cpszFmt, args, NULL); +} + +int std_vsnprintf(char *pszDest, int nDestSize, + const char *cpszFmt, + AEEVaList args) +/* + Same as std_vstrlprintf with the additional support of floating point + conversion specifiers - %e, %f, %g and %a +*/ +{ + return std_strlprintf_inner(pszDest, nDestSize, cpszFmt, args, FormatFloat); +} + +int std_strlprintf(char *pszDest, int nDestSize, const char *pszFmt, ...) +{ + int nRet; + AEEVaList args; + + AEEVA_START(args, pszFmt); + + nRet = std_vstrlprintf(pszDest, nDestSize, pszFmt, args); + + AEEVA_END(args); + + return nRet; +} + +int std_snprintf(char *pszDest, int nDestSize, const char *pszFmt, ...) +/* + Same as std_strlprintf with the additional support of floating point + conversion specifiers - %e, %f, %g and %a +*/ +{ + int nRet; + AEEVaList args; + + AEEVA_START(args, pszFmt); + + nRet = std_vsnprintf(pszDest, nDestSize, pszFmt, args); + + AEEVA_END(args); + + return nRet; +} diff --git a/src/symbols.lst b/src/symbols.lst new file mode 100644 index 0000000..5e0458d --- /dev/null +++ b/src/symbols.lst @@ -0,0 +1,56 @@ +/* + * 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. + */ +{ + global: + remote_handle_open; + remote_handle_invoke; + remote_handle_close; + remote_handle_control; + remote_session_control; + remote_mmap; + remote_munmap; + remote_mmap64; + remote_munmap64; + remote_register_buf; + remote_register_buf_attr; + remote_register_fd; + remote_register_dma_handle; + remote_register_dma_handle_attr; + remote_set_mode; + remote_handle64_open; + remote_handle64_invoke; + remote_handle64_close; + remote_handle64_control; + rpcmem_alloc; + rpcmem_free; + rpcmem_to_fd; + rpcmem_init; + rpcmem_deinit; + local: *; +}; |