diff options
author | Anthony Stange <stange@google.com> | 2019-11-15 02:05:30 -0800 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-11-15 02:05:30 -0800 |
commit | 3b85c51d2792e75fbc3dba18b2a8cd8669068d2f (patch) | |
tree | a1dda0b33986404edd6c17685c91df8cbd94d57f | |
parent | b01fa3f23affa99a4c5207f9081d1d7c13965f4d (diff) | |
parent | d6d6e3bba244e40e6043bd687f4cacf090a767b5 (diff) | |
download | fastrpc-3b85c51d2792e75fbc3dba18b2a8cd8669068d2f.tar.gz |
Import fastrpc code from upstream
am: d6d6e3bba2
Change-Id: Id8b1f1d165d7e362f2150f5f1f69007d45de2265
87 files changed, 28236 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8251c58 --- /dev/null +++ b/Makefile @@ -0,0 +1,84 @@ + +CFLAGS = -fno-short-enums -U_DEBUG -DARM_ARCH_7A -DLE_ENABLE -DUSE_SYSLOG -Iinc -Isrc -DDEFAULT_DOMAIN_ID=3 +LDFLAGS = -fPIC -pie -Wl,--version-script=src/symbols.lst -ldl -lpthread -lm + + + +prefix := /usr/local +bindir := $(prefix)/bin +libdir := $(prefix)/lib + + +LIBADSPRPC_SRC_FILES := src/fastrpc_apps_user.c \ + src/remotectl_stub.c \ + src/listener_android.c \ + src/adsp_current_process_stub.c \ + src/adsp_current_process1_stub.c \ + src/apps_std_skel.c \ + src/apps_std_imp.c \ + src/apps_mem_imp.c \ + src/apps_mem_skel.c \ + src/rpcmem_android.c \ + src/apps_remotectl_skel.c \ + src/std.c \ + src/std_path.c \ + src/std_mem.c \ + src/std_dtoa.c \ + src/std_strlprintf.c \ + src/BufBound.c \ + src/std_SwapBytes.c \ + src/smath.c \ + src/atomic.c \ + src/cae.c \ + src/adspmsgd_apps_skel.c \ + src/adspmsgd_adsp_stub.c \ + src/adspmsgd_adsp1_stub.c \ + src/adspmsgd_apps.c \ + src/platform_libs.c \ + src/pl_list.c \ + src/log_config.c \ + src/gpls.c \ + src/adsp_perf_stub.c \ + src/fastrpc_perf.c \ + src/mod_table.c + +LIBADSPRPC_OBJ := $(LIBADSPRPC_SRC_FILES:.c=.o) + +LIBDEFAULT_LISTENER_SRC_FILES := src/adsp_default_listener.c \ + src/adsp_default_listener_stub.c \ + src/std.c \ + src/std_mem.c + +LIBDEFAULT_LISTENER_OBJ := $(LIBDEFAULT_LISTENER_SRC_FILES:.c=.o) + +ADSPRPCD_SRC_FILES := src/cdsprpcd.c + +ADSPRPCD_OBJ := $(ADSPRPCD_SRC_FILES:.c=.o) + +%.o: %.c + $(CC) -fpic -pie $(CFLAGS) -c $< -o $@ + +cdsprpcd: $(ADSPRPCD_OBJ) libcdsp_default_listener.so + echo $(LD) -fpic -pie $(LDFLAGS) -o cdsprpcd + $(CC) -fpic -pie -fPIC -pie -Wl,--version-script=src/symbols.lst -ldl -lpthread -lm $(ADSPRPCD_OBJ) -o cdsprpcd -lcdsp_default_listener -L. + echo "cdsprpcd built successfully" + +LDFLAGS = -fPIC -pie -Wl,--version-script=src/symbols.lst -shared -ldl -lpthread -lm + +libcdsp_default_listener.so: $(LIBDEFAULT_LISTENER_OBJ) libcdsprpc.so + echo $(LD) -fpic -pie -shared $(LDFLAGS) -o libcdsp_default_listener.so + $(CC) -fpic -pie -shared -fPIC -pie -Wl,--version-script=src/adsp_def_symbols.lst -ldl -lpthread -lm $(LIBDEFAULT_LISTENER_OBJ) -o libcdsp_default_listener.so -lcdsprpc -L. + echo "libcdsp_default_listener built successfully" + +libcdsprpc.so: $(LIBADSPRPC_OBJ) + echo $(LD) -fpic -pie -shared $(LDFLAGS) -o libcdsprpc.so + $(CC) -fpic -pie -shared $(LDFLAGS) $(LIBADSPRPC_OBJ) -o libcdsprpc.so + echo "libcdsprpc built successfully" + +all: libcdsprpc.so libcdsp_default_listener.so cdsprpcd + echo "All binaries built" + +install: libcdsprpc.so libcdsp_default_listener.so cdsprpcd + @install -D -m 755 libcdsprpc.so $(DESTDIR)$(libdir)/libcdsprpc.so + @install -D -m 755 libcdsp_default_listener.so $(DESTDIR)$(libdir)/libcdsp_default_listener.so + @install -D -m 755 cdsprpcd $(DESTDIR)$(bindir)/cdsprpcd
\ No newline at end of file diff --git a/inc/AEEBufBound.h b/inc/AEEBufBound.h new file mode 100644 index 0000000..583844c --- /dev/null +++ b/inc/AEEBufBound.h @@ -0,0 +1,567 @@ +/** + * 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 AEEBUFBOUND_H +#define AEEBUFBOUND_H +/*============================================================================== + +FILE: AEEBufBound.h + +SERVICES: + BufBound APIs + +GENERAL DESCRIPTION: + BufBound 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: + Fri Aug 08 17:38:29 2003: Created + +==============================================================================*/ + +typedef struct BufBound +{ + char* pcBuf; /* original buffer */ + char* pcWrite; /* write pointer */ + char* pcEnd; /* first illegal write pointer */ +} BufBound; + +#ifdef __cplusplus +extern "C" { +#endif /* #ifdef __cplusplus */ + +extern void BufBound_Init(BufBound *me, char *pBuf, int nLen); +extern void BufBound_Write(BufBound *me, const char *pc, int nLen); +extern void BufBound_Putc(BufBound *me, char c); +extern void BufBound_Putnc(BufBound *me, char c, int nCount); +extern void BufBound_ForceNullTerm(BufBound *me); +extern void BufBound_Puts(BufBound *me, const char* cpsz); +extern void BufBound_Advance(BufBound *me, int nLen); +extern void BufBound_WriteLE(BufBound* me, + const void *pvSrc, int nSrcSize, + const char *pszFields); +extern void BufBound_WriteBE(BufBound* me, + const void *pvSrc, int nSrcSize, + const char *pszFields); +extern int BufBound_BufSize(BufBound *me); +extern int BufBound_Left(BufBound* me); +extern int BufBound_ReallyWrote(BufBound* me); +extern int BufBound_Wrote(BufBound* me); + +static __inline int BufBound_IsFull(BufBound* me) +{ + return (BufBound_Left(me) <= 0); +} + +// Deprecated: +static __inline int BufBound_IsCounter(BufBound* me) +{ + return BufBound_BufSize(me) == 0; +} + +#ifdef __cplusplus +} +#endif /* #ifdef __cplusplus */ + + +/*===================================================================== +======================================================================= +DATA STRUCTURE DOCUMENTATION +======================================================================= + +BufBound + +Description: + An BufBound keeps track of whether appending to a bounded buffer + has overflowed. + +Definition: + typedef struct BufBound + { + char* pcBuf; + char* pcWrite; + char* pcEnd; + } BufBound; + +Members: + pcBuf: original start pointer + pcWrite: current write location + pcEnd: first illegal write position + +See Also: + BufBound Interface + +======================================================================= +INTERFACE DOCUMENTATION +======================================================================= +BufBound Interface + + BufBound is a statically-linked interface. + + BufBound provides functions for safely appending to a character buffer. On + initialization, the buffer start address and size are provided. Subsequent + write operations are checked against the buffer bounds. + + Once the buffer bounds are exceeded, no bytes will be written but the + BufBound will continue to increment its internal "write pointer" to reflect + the number of bytes that would have been written (had the bounds not been + exceeded). + + When initialized with a buffer size of zero, a BufBound simply counts the + number of bytes that would be required to contain the result. This design + accommodates implementations that use the same logic for generating output + and measuring the space required for generated output. + + BufBound protects clients from numerical overflow by limiting the write + pointer to a maximum offset of INT_MAX from the start of the buffer. + Functions that write data into the buffer safely ignore negative size inputs + (Write and Putnc). + +======================================================================= +BufBound_Init() + +Description: + initialize a BufBound for appending to a buffer + +Prototype: + + void BufBound_Init(BufBound *me, char *pBuf, int nLen); + +Parameters: + me: the BufBound + pBuf: the bounded buffer + nLen: size of pBuf, in bytes + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_Write() + +Description: + Appends some number of bytes to a BufBound, if possible. + + When a negative size is passed, it is safely treated as zero. + +Prototype: + + void BufBound_Write(BufBound *me, const char *pc, int nLen); + +Parameters: + me: the BufBound + pc: pointer to bytes to append + int nLen: number of bytes to write + +Return Value: + None + +Comments: + If the BufBound has overflowed, no bytes are written, but pcWrite is + *always* advanced by nLen. + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_Advance() + +Description: + + Moves the write pointer. Advance is like a relative seek operation. It + does not change the contents of the buffer, so when using a forward seek + (positive advance) be careful of advancing over uninitialized data. + + Negative numbers will decrease the write pointer down to 0 (the start of + the buffer) and not below. Positive numbers will increase the write + pointer up to offset INT_MAX and not beyond. + +Prototype: + + void BufBound_Advance(BufBound *me, int nDelta); + +Parameters: + me: the BufBound + int nLen: number of bytes to advance + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_Putc() + +Description: + Appends one byte to a BufBound, if possible. + +Prototype: + + void BufBound_Putc(BufBound *me, char c); + +Parameters: + me: the BufBound + c: the byte + +Return Value: + None + +Comments: + If the BufBound has overflowed, no byte is written, but pcWrite is + *always* advanced by 1. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Putnc() + +Description: + Appends a byte to a BufBound repeatedly. + + When a negative size is passed, it is safely treated as zero. + +Prototype: + + void BufBound_Putnc(BufBound *me, char c, int nCount); + +Parameters: + me: the BufBound + c: the byte + nCount: number of times to append c + +Return Value: + None + +Comments: + If the BufBound has overflowed, no byte is written, but pcWrite is + *always* advanced by nCount. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_ForceNullTerm() + +Description: + Appends a null terminating character to a BufBound, if possible. + If the BufBound has overflowed, the last legal location is + set to '\0'. + +Prototype: + void BufBound_ForceNullTerm(BufBound *me); + +Parameters: + me: the BufBound + +Return Value: + None + +Comments: + pcWrite is *always* advanced by 1. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Puts() + +Description: + Appends a null-terminated string to a BufBound, if possible + +Prototype: + + void BufBound_Puts(BufBound *me, const char* cpsz); + +Parameters: + me: the BufBound + cpsz: the string to append + +Return Value: + +Comments: + If the BufBound has overflowed, no bytes are written, but pcWrite is + *always* advanced by strlen(cpsz). + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_BufSize() + +Description: + Returns the size of the buffer owned by the BufBound. This is + the same as the number passed to BufBound_Init (MAXed with zero). + +Prototype: + + int BufBound_IsCounter(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + 1 if the BufBound is a counter, 0 otherwise + +Comments: + None + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Left() + +Description: + Returns the number of bytes the BufBound can still accomodate, + without overflowing. If overflow has occurred, it will return + a negative number. + +Prototype: + + int BufBound_Left(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + The number of bytes the BufBound can still accomodate, + without overflowing. + +Comments: + The return value may be negative, if overflow has already occurred. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_ReallyWrote() + +Description: + Returns the number of bytes actually written to the BufBound, + not including any overflow. + +Prototype: + + int BufBound_ReallyWrote(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + The number of bytes actually written to the BufBound, + not including any overflow. + +Comments: + None + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Wrote() + +Description: + + Returns the number of bytes written to the BufBound, including any + overflow, up to INT_MAX. + +Prototype: + + int BufBound_Wrote(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + + The number of bytes written to the BufBound, including any overflow. + +Comments: + None + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_IsFull() + +Description: + Tests whether an AEEBuffBound has overflowed. + +Prototype: + + int BufBound_IsFull(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + 1 if the BufBound has overflowed, 0 otherwise + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_WriteLE() + +Description: + + Writes data while translating numeric values between host byte ordering and + "little endian" byte ordering. + + The input buffer is treated as an array of structures. The 'abySizes' + parameter describes the sizes of fields in the structure. + + When the host byte ordering matches the target byte ordering (little + endian) this operation is equivalent to BufBound_Write(). + +Prototype: + + void BufBound_WriteLE(BufBound* me, + const void *pvSrc, int nSrcSize, + const unsigned char *pszFields); + +Parameters: + me: the BufBound + pvSrc: the source buffer + nSrcSize: number of bytes to copy from the source buffer + pszFields: Description of the fields that comprise the source data, + as defined in std_CopyLE. + +Return Value: + None + +See Also: + BufBound_WriteBE, std_CopyLE + +======================================================================= + +BufBound_WriteBE() + +Description: + + BufBounf_WriteBE() has the same semantics as BufBound_WriteLE() except it + copies between host byte ordering and big-endian ("network") byte order. + + See BufBound_WriteLE() for more details. + + +Prototype: + + void BufBound_WriteBE(BufBound* me, + const void *pvSrc, int nSrcSize, + const unsigned char *pszFields); + +Parameters: + me: the BufBound + pvSrc: the source buffer + nSrcSize: number of bytes to copy from the source buffer + pszFields: Description of the fields that comprise the source data, + as defined in std_CopyLE. + +Return Value: + None + +See Also: + BufBound_WriteLE, std_CopyBE + +======================================================================= */ +#endif /* #ifndef AEEBUFBOUND_H */ + diff --git a/inc/AEEQList.h b/inc/AEEQList.h new file mode 100644 index 0000000..1b3b941 --- /dev/null +++ b/inc/AEEQList.h @@ -0,0 +1,851 @@ +/** + * 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: AEEQList.h + +GENERAL DESCRIPTION: Doubly-linked circular list implementation + +===========================================================================*/ +#ifndef _AEEQLIST_H_ +#define _AEEQLIST_H_ + + +typedef struct QNode QNode; +struct QNode { + QNode *pNext; + QNode *pPrev; +}; + +#define QLIST_DEFINE_INIT(f) QList f = { { &f.n, &f.n } } + +typedef struct QList QList; +struct QList { + QNode n; +}; + + + +static __inline void QNode_InsPrev(QNode *me, QNode *pn) +{ + QNode *pPrev = me->pPrev; + + pn->pNext = me; + pn->pPrev = pPrev; + pPrev->pNext = pn; + me->pPrev = pn; +} + + +static __inline void QNode_InsNext(QNode *me, QNode *pn) +{ + QNode *pNext = me->pNext; + + pn->pPrev = me; + pn->pNext = pNext; + pNext->pPrev = pn; + me->pNext = pn; +} + + + +static __inline void QNode_Dequeue(QNode *me) +{ + QNode *pNext = me->pNext; + QNode *pPrev = me->pPrev; + + pPrev->pNext = pNext; + pNext->pPrev = pPrev; +} + +static __inline void QNode_CtorZ(QNode *me) +{ + me->pNext = me->pPrev = 0; +} + +static __inline int QNode_IsQueuedZ(QNode *me) +{ + return (0 != me->pNext); +} + +static __inline void QNode_DequeueZ(QNode *me) +{ + if (QNode_IsQueuedZ(me)) { + QNode_Dequeue(me); + me->pNext = me->pPrev = 0; + } +} + +//-------------------------------------------------------------------- +//-- QList functions ---------------------------------------------- +//-------------------------------------------------------------------- + + +static __inline void QList_Zero(QList *me) +{ + me->n.pNext = me->n.pPrev = &me->n; +} + + +static __inline void QList_Ctor(QList *me) +{ + QList_Zero(me); +} + + +static __inline int QList_IsEmpty(QList *me) +{ + return me->n.pNext == &me->n; +} + +static __inline int QList_IsNull(QList *me) +{ + return ((0 == me->n.pNext) && (0 == me->n.pPrev)); +} + + +static __inline void QList_AppendNode(QList *me, QNode *pn) +{ + QNode_InsPrev(&me->n, pn); +} + + +static __inline void QList_PrependNode(QList *me, QNode *pn) +{ + QNode_InsNext(&me->n, pn); +} + + +static __inline void QList_CtorFrom(QList *me, QList *psrc) +{ + QNode *s = &psrc->n; + QNode *d = &me->n; + + s->pNext->pPrev = d; + d->pPrev = s->pPrev; + d->pNext = s->pNext; + s->pPrev->pNext = d; + + QList_Zero(psrc); +} + + + +static __inline void QList_AppendList(QList *me, QList *psrc) +{ + QNode *s = &psrc->n; + QNode *d = &me->n; + QNode *dp = d->pPrev; + QNode *sn = s->pNext; + QNode *sp; + + sn->pPrev = dp; + dp->pNext = sn; + d->pPrev = (sp = s->pPrev); + sp->pNext = d; + + QList_Zero(psrc); +} + + +#define QLIST_FOR_ALL(pList, pNode) \ + for ((pNode) = (pList)->n.pNext; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pNext) + +#define QLIST_FOR_REST(pList, pNode) \ + for (; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pNext) + +#define QLIST_REV_FOR_ALL(pList, pNode) \ + for ((pNode) = (pList)->n.pPrev; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pPrev) + +#define QLIST_REV_FOR_REST(pList, pNode) \ + for (; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pPrev) + +/* Allows dequeing QNodes during iteration */ +#define QLIST_NEXTSAFE_FOR_ALL(pList, pNode, pNodeNext) \ + for ((pNode) = (pList)->n.pNext, (pNodeNext) = (pNode)->pNext; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNodeNext), (pNodeNext) = (pNode)->pNext) + +static __inline QNode *QList_GetFirst(QList *me) +{ + QNode *pn = me->n.pNext; + + return (pn == &me->n ? 0 : pn); +} + +static __inline QNode *QList_GetLast(QList *me) +{ + QNode *pn = me->n.pPrev; + + return (pn == &me->n ? 0 : pn); +} + +static __inline QNode *QList_Pop(QList *me) +{ + QNode *pn = me->n.pNext; + QNode *pnn = pn->pNext; + + me->n.pNext = pnn; + pnn->pPrev = &me->n; + + return (pn == &me->n ? 0 : pn); +} + +static __inline QNode *QList_PopZ(QList *me) +{ + QNode *pn = QList_Pop(me); + if (0 != pn) { + QNode_CtorZ(pn); + } + return pn; +} + +static __inline QNode *QList_PopLast(QList *me) +{ + QNode *pp = me->n.pPrev; + QNode *ppp = pp->pPrev; + + me->n.pPrev = ppp; + ppp->pNext = &me->n; + + return (pp == &me->n ? 0 : pp); +} + +static __inline QNode *QList_PopLastZ(QList *me) +{ + QNode *pn = QList_PopLast(me); + if (0 != pn) { + QNode_CtorZ(pn); + } + return pn; +} + +/*===================================================================== +======================================================================= +DATA STRUCTURE DOCUMENTATION +======================================================================= + +QNode + +Description: + Qnode is the structure that is queued. One or more Qnodes may be + embedded in other structures. An object can contain multiple QNodes if + it needs to be in different lists at the same time. + +Definition: + + typedef struct QNode QNode; + struct QNode { + QNode *pNext; + QNode *pPrev; + }; + +Members: + +See Also: + +======================================================================= + +QList + +Description: + QList keeps a doubly-linked list of QNode structures. + Each queue is represented by a 'head' node, not a head pointer, + simplifying and streamlining many operations. + Because it is doubly-linked it permits constant-time insertion or removal + of items or of entire queues. + Because it is circular it permits constant-time operations at both the + tail and the head of the queue. Circularity also streamlines some + operations by eliminating conditional branches. + + General rules: + QLists are always in a defined state; they should be constructed + before use, using one of the supplied Ctor...() functions. + QNodes do not track queued vs. unqueued state. The client should + never dequeue an un-queued node or queue an already-queued node. + When not queued, QNode internal state is undefined. A client may + implement marking and assertion externally. + +Definition: + + typedef struct QList QList; + struct QList { + QNode n; + }; + +Members: + +See Also: + +======================================================================= +INTERFACE DOCUMENTATION +======================================================================= +QNode Interface + + QNode is a statically-linked interface. + +======================================================================= +QNode_CtorZ() + +Description: + Zero initialize a QNode. + +Prototype: + + void QNode_CtorZ(QNode *me); + +Parameters: + me: the QNode + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + QNode_IsQueued(), QNode_DequeueZ(), QList_PopZ() + +======================================================================= +QNode_IsQueuedZ() + +Description: + Whether a QNode belongs in a Queue. + +Prototype: + + int QNode_IsQueuedZ(QNode *me); + +Parameters: + me: the QNode + +Return Value: + None + +Comments: + None + +Side Effects: + Does not work if a node needs to live at address 0x0. + +See Also: + QNode_CtorZ(), QNode_DequeueZ(), QList_PopZ() + +======================================================================= +QNode_DequeueZ() + +Description: + Dequeue a QNode if it is in a queue. Idempotent operation. + +Prototype: + + void QNode_DequeueZ(QNode *me); + +Parameters: + me: the QNode + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + QNode_CtorZ(), QNode_IsQueued(), QList_PopZ() + +======================================================================= + +QNode_InsPrev() + +Description: + insert a node before this one. + +Prototype: + static __inline void QNode_InsPrev(QNode *me, QNode *pn) + +Parameters: + me: the QNode + pn: the node to be inserted. +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +QNode_InsNext() + +Description: + insert a node after this one. + +Prototype: + static __inline void QNode_InsNext(QNode *me, QNode *pn) + +Parameters: + me: the QNode + pn: the node to be inserted. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QNode_Dequeue() + +Description: + dequeue this node. + +Prototype: + static __inline void QNode_Dequeue(QNode *me) + +Parameters: + me: the QNode to be dequeued + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList Interface + + QList is a statically-linked interface. It provides a Queue of + doubly linked nodes. + +======================================================================= +QList_Zero() + +Description: + discard all queued nodes. + +Prototype: + + void QList_Zero(QList *me) + +Parameters: + me: the QList + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_Ctor() + +Description: + Initialize a queue to an empty state + +Prototype: + + void QList_Ctor(QList *me) + +Parameters: + me: the QList + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_IsEmpty() + +Description: + Check whether queue is empty. + +Prototype: + + int QList_IsEmpty(QList *me) + +Parameters: + me: the QList + +Return Value: + TRUE if queue is empty. + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_AppendNode() + +Description: + Append the node to the queue. Make it the last 'next' (and the + first 'prev') + +Prototype: + + void QList_AppendNode(QList *me, QNode *pn) + +Parameters: + me: the QList + pn: the node to append. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_PrependNode() + +Description: + Prepend a node to the queue. Make it the first 'next' (and the + last 'prev'). + +Prototype: + + void QList_PrependNode(QList *me, QNode *pn) + +Parameters: + me: the QList + pn: the node to prepend. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_CtorFrom() + +Description: + Move nodes from one queue to a newly constructed queue. + Weird aliasing voodoo allows this to work without conditional branches, even + when psrc is empty. In that case, "s->pNext->pPrev = d" overwrites s->pPrev with d, + so that "s->pPrev->pNext = d" will later overwrite d->pNext with d. + +Prototype: + + void QList_CtorFrom(QList *me, QList *psrc) + +Parameters: + me: the QList + psrc: the Qlist from + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_AppendList() + +Description: + Move all nodes from a source queue to the end of this queue. + Note that weird aliasing voodoo allows this to work without conditional + branches when psrc is empty. A summary: + + SNP = DP => SP = DP, because SNP aliases SP + DPN = SN => DPN = S + DP = SP => DP = DP, because SP was overwritten with DP + SPN = D => DPN = D + +Prototype: + + void QList_AppendList(QList *me, QList *psrc) + +Parameters: + me: the QList + psrc: the source Qlist. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_GetFirst() + +Description: + Get the first item on the queue + +Prototype: + + QNode *QList_GetFirst(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty. + +Comments: + None + +Side Effects: + None + +See Also: + QList_GetLast + +======================================================================= +QList_GetLast() + +Description: + Get the last item on the queue + +Prototype: + + QNode *QList_GetLast(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty. + +Comments: + None + +Side Effects: + None + +See Also: + QList_GetFirst + +======================================================================= +QList_Pop() + +Description: + Remove and return the first item on the queue (FIFO). + +Prototype: + + QNode *QList_Pop(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_PopZ, QNode_PopLast(), QNode_PopLastZ, QNode_CtorZ(), QNode_IsQueued(), + QNode_DequeueZ() + +======================================================================= +QList_PopZ() + +Description: + Remove and return the first item on the queue (FIFO). Same as QList_Pop(), + except the node retured is zero-initialized. + +Prototype: + + QNode *QList_PopZ(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_Pop, QNode_PopLast(), QNode_PopLastZ, QNode_CtorZ(), QNode_IsQueued(), + QNode_DequeueZ() + +======================================================================= +QList_PopLast() + +Description: + Remove and return the first item on the queue (FILO). + +Prototype: + + QNode *QList_PopLast(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_PopLastZ, QNode_Pop(), QNode_PopZ, QNode_CtorZ(), QNode_IsQueued(), + QNode_DequeueZ() + +======================================================================= + +QList_IsNull() + +Description: +Checks if the QList is null or not. + +Prototype: +static __inline int QList_IsNull(QList *me) + +Parameters: + me: the QList + +Return Value: + True or False. + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +QList_PopLastZ() + +Description: + Remove and return the first item on the queue (FILO). + Same as QList_PopLast(), except the node retured is zero-initialized. + +Prototype: + + QNode *QList_PopLastZ(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_Pop(), QNode_PopZ, QNode_CtorZ(), QNode_IsQueued(), QNode_DequeueZ() + +=====================================================================*/ +#endif // _AEEQLIST_H_ diff --git a/inc/AEEStdDef.h b/inc/AEEStdDef.h new file mode 100644 index 0000000..230950f --- /dev/null +++ b/inc/AEEStdDef.h @@ -0,0 +1,1146 @@ +/** + * 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 AEESTDDEF_H +#define AEESTDDEF_H +/* +======================================================================= + +FILE: AEEStdDef.h + +DESCRIPTION: definition of basic types, constants, + preprocessor macros + +======================================================================= +*/ + +#include <stdint.h> + +#if defined(COMDEF_H) /* guards against a known re-definer */ +#define _BOOLEAN_DEFINED +#define _UINT32_DEFINED +#define _UINT16_DEFINED +#define _UINT8_DEFINED +#define _INT32_DEFINED +#define _INT16_DEFINED +#define _INT8_DEFINED +#define _UINT64_DEFINED +#define _INT64_DEFINED +#define _BYTE_DEFINED +#endif /* #if !defined(COMDEF_H) */ + +/* ----------------------------------------------------------------------- +** Standard Types +** ----------------------------------------------------------------------- */ + +/* The following definitions are the same accross platforms. This first +** group are the sanctioned types. +*/ +#ifndef _BOOLEAN_DEFINED +typedef unsigned char boolean; /* Boolean value type. */ +#define _BOOLEAN_DEFINED +#endif + +#ifndef _UINT32_DEFINED +typedef uint32_t uint32; /* Unsigned 32 bit value */ +#define _UINT32_DEFINED +#endif + +#ifndef _UINT16_DEFINED +typedef unsigned short uint16; /* Unsigned 16 bit value */ +#define _UINT16_DEFINED +#endif + +#ifndef _UINT8_DEFINED +typedef unsigned char uint8; /* Unsigned 8 bit value */ +#define _UINT8_DEFINED +#endif + +#ifndef _INT32_DEFINED +typedef int32_t int32; /* Signed 32 bit value */ +#define _INT32_DEFINED +#endif + +#ifndef _INT16_DEFINED +typedef signed short int16; /* Signed 16 bit value */ +#define _INT16_DEFINED +#endif + +#ifndef _INT8_DEFINED +typedef signed char int8; /* Signed 8 bit value */ +#define _INT8_DEFINED +#endif + +#if defined(__GNUC__) +#define __int64 long long +#endif + +#ifndef _UINT64_DEFINED +typedef unsigned __int64 uint64; /* Unsigned 64 bit value */ +#define _UINT64_DEFINED +#endif + +#ifndef _INT64_DEFINED +typedef __int64 int64; /* Signed 64 bit value */ +#define _INT64_DEFINED +#endif + +#ifndef _BYTE_DEFINED +typedef unsigned char byte; /* byte type */ +#define _BYTE_DEFINED +#endif + + +#ifndef _AEEUID_DEFINED +typedef uint32 AEEUID; +#define _AEEUID_DEFINED +#endif + +#ifndef _AEEIID_DEFINED +typedef uint32 AEEIID; +#define _AEEIID_DEFINED +#endif + +#ifndef _AEECLSID_DEFINED +typedef uint32 AEECLSID; +#define _AEECLSID_DEFINED +#endif + +#ifndef _AEEPRIVID_DEFINED +typedef uint32 AEEPRIVID; +#define _AEEPRIVID_DEFINED +#endif + +#ifndef _AECHAR_DEFINED +typedef uint16 AECHAR; +#define _AECHAR_DEFINED +#endif + +#ifndef _AEERESULT_DEFINED +typedef int AEEResult; +#define _AEERESULT_DEFINED +#endif + +/* ----------------------------------------------------------------------- +** Function Calling Conventions +** ----------------------------------------------------------------------- */ + +#ifndef CDECL +#ifdef _MSC_VER +#define CDECL __cdecl +#else +#define CDECL +#endif /* _MSC_VER */ +#endif /* CDECL */ + +/* ----------------------------------------------------------------------- +** Constants +** ----------------------------------------------------------------------- */ + +#ifndef TRUE +#define TRUE 1 /* Boolean true value. */ +#endif + +#ifndef FALSE +#define FALSE 0 /* Boolean false value. */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef MIN_INT8 +#define MIN_INT8 -128 +#endif +#ifndef MIN_INT16 +#define MIN_INT16 -32768 +#endif +#ifndef MIN_INT32 +#define MIN_INT32 (~0x7fffffff) /* -2147483648 is unsigned */ +#endif +#ifndef MIN_INT64 +#define MIN_INT64 (~0x7fffffffffffffffLL) /* -9223372036854775808 is unsigned */ +#endif + +#ifndef MAX_INT8 +#define MAX_INT8 127 +#endif +#ifndef MAX_INT16 +#define MAX_INT16 32767 +#endif +#ifndef MAX_INT32 +#define MAX_INT32 2147483647 +#endif +#ifndef MAX_INT64 +#define MAX_INT64 9223372036854775807LL +#endif + +#ifndef MAX_UINT8 +#define MAX_UINT8 255 +#endif +#ifndef MAX_UINT16 +#define MAX_UINT16 65535 +#endif +#ifndef MAX_UINT32 +#define MAX_UINT32 4294967295u +#endif +#ifndef MAX_UINT64 +#define MAX_UINT64 18446744073709551615uLL +#endif + +#ifndef MIN_AECHAR +#define MIN_AECHAR 0 +#endif +#ifndef MAX_AECHAR +#define MAX_AECHAR 65535 +#endif + + +/* ----------------------------------------------------------------------- +** Preprocessor helpers +** ----------------------------------------------------------------------- */ +#define __STR__(x) #x +#define __TOSTR__(x) __STR__(x) +#define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__) + +/* ----------------------------------------------------------------------- +** Types for code generated from IDL +** ----------------------------------------------------------------------- */ + +#ifndef __QIDL_WCHAR_T_DEFINED__ +#define __QIDL_WCHAR_T_DEFINED__ +typedef uint16 _wchar_t; +#endif + +/* __STRING_OBJECT__ will be deprecated in the future */ +#if !defined(__QIDL_STRING_OBJECT_DEFINED__) && !defined(__STRING_OBJECT__) +#define __QIDL_STRING_OBJECT_DEFINED__ +#define __STRING_OBJECT__ +typedef struct _cstring_s { + char* data; + int dataLen; + int dataLenReq; +} _cstring_t; + +typedef struct _wstring_s { + _wchar_t* data; + int dataLen; + int dataLenReq; +} _wstring_t; +#endif /* __QIDL_STRING_OBJECT_DEFINED__ */ + +/* +======================================================================= + DATA STRUCTURES DOCUMENTATION +======================================================================= + +boolean + +Description: + This type is used to express boolean values (TRUE or FALSE). + +Definition: + typedef unsigned char boolean + +See Also: + byte + int8 + int16 + int32 + int64 + uint32 + uint16 + uint8 + uint64 + +======================================================================= + +uint32 + +Description: + This is a 32-bit unsigned integer. + +Definition: + typedef uint32_t uint32 + +See Also: + boolean + byte + int8 + int16 + int32 + int64 + uint8 + uint16 + uint64 + +======================================================================= + +uint16 + +Description: + This is a 16-bit unsigned integer. + +Definition: + typedef unsigned short uint16 + +See Also: + boolean + byte + int8 + int16 + int32 + int64 + uint8 + uint32 + uint64 + +======================================================================= + +uint8 + +Description: + This is an 8-bit unsigned integer. + +Definition: + typedef unsigned char uint8 + +See Also: + boolean + byte + int8 + int16 + int32 + int64 + uint16 + uint32 + uint64 + +======================================================================= + +int32 + +Description: + This is a 32-bit signed integer. + +Definition: + typedef int32_t int32 + +See Also: + boolean + byte + int8 + int16 + int64 + uint8 + uint16 + uint32 + uint64 + +======================================================================= + +int16 + +Description: + This is a 16-bit signed integer. + +Definition: + typedef signed short int16 + +See Also: + boolean + byte + int8 + int32 + int64 + uint8 + uint16 + uint32 + uint64 + +======================================================================= + +int8 + +Description: + This is an 8-bit signed integer. + +Definition: + typedef signed char int8 + +See Also: + boolean + byte + int16 + int32 + int64 + uint8 + uint16 + uint32 + uint64 + +======================================================================= + +uint64 + +Description: + This is a 64-bit unsigned integer. + +Definition: + typedef unsigned __int64 uint64 + +See Also: + boolean + byte + int8 + int16 + int32 + int64 + uint8 + uint16 + uint32 + +======================================================================= + +int64 + +Description: + This is a 64-bit signed integer. + +Definition: + typedef __int64 int64 + +See Also: + boolean + byte + int8 + int16 + int32 + uint8 + uint16 + uint32 + uint64 + +======================================================================= + +byte + +Description: + This is a byte. + +Definition: + typedef unsigned char byte + +See Also: + boolean + int8 + int16 + int32 + int64 + uint8 + uint16 + uint32 + uint64 + +======================================================================= + +AEEUID + +Description: + This is a BREW unique ID. Used to express unique types, interfaces, classes + groups and privileges. The BREW ClassID Generator generates + unique IDs that can be used anywhere you need a new AEEIID, AEECLSID, + or AEEPRIVID. + +Definition: + typedef uint32 AEEUID + +See Also: + AECHAR + AEECLSID + AEEIID + AEEPRIVID + AEEResult + +======================================================================= + +AEEIID + +Description: + This is an interface ID type, used to denote a BREW interface. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEEIID + +See Also: + AECHAR + AEECLSID + AEEPRIVID + AEEResult + AEEUID + +======================================================================= + +AEECLSID + +Description: + This is a classe ID type, used to denote a BREW class. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEECLSID + +See Also: + AECHAR + AEECLSIDs + AEEIID + AEEPRIVID + AEEResult + AEEUID + +======================================================================= + +AEEPRIVID + +Description: + This is a privilege ID type, used to express a privilege. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEEPRIVID + +See Also: + AECHAR + AEECLSID + AEEIID + AEEResult + AEEUID + +======================================================================= + +AECHAR + +Description: + This is a 16-bit character type. + +Definition: + typedef uint16 AECHAR + +See Also: + AEEPRIVID + AEECLSID + AEEIID + AEEResult + AEEUID + +======================================================================= + +AEEResult + +Description: + This is the standard result type. + +Definition: + typedef int AEEResult + +See Also: + AECHAR + AEEPRIVID + AEECLSID + AEEIID + AEEUID + +======================================================================= + +_wchar_t + +Description: + This is a 16-bit character type corresponding to the IDL 'wchar' + type. + +Definition: + typedef uint16 _wchar_t + +See Also: + _cstring_t + _wstring_t + +======================================================================= + +_cstring_t + +Description: + This structure is used to represent an IDL string when used inside a + sequence or union. + +Definition: + typedef struct _cstring_s { + char* data; + int dataLen; + int dataLenReq; + } _cstring_t; + +Members: + data : A pointer to the NULL-terminated string. + dataLen : The size, in chars, of the buffer pointed to by 'data', + including the NULL terminator. This member is only used + when the structure is part of an rout or inrout + parameter, but must be supplied by the caller as an + input in these cases. + dataLenReq : The size that would have been required to store the + entire result string. This member is only used when the + structure is part of an rout or inrout parameter, when + it is an output value set by the callee. The length of + the returned string (including the NULL terminator) + after a call is the minimum of dataLen and dataLenReq. + +See Also: + _wchar_t + _wstring_t + +======================================================================= + +_wstring_t + +Description: + This structure is used to represent an IDL wstring when used inside a + sequence or union. + +Definition: + typedef struct _wstring_s { + _wchar_t* data; + int dataLen; + int dataLenReq; + } _wstring_t; + +Members: + data : A pointer to the NULL-terminated wide string. + dataLen : The size, in 16-bit characters, of the buffer pointed to + by 'data', including the NULL terminator. This member + is only used when the structure is part of an rout or + inrout parameter, but must be supplied by the caller as + an input in these cases. + dataLenReq : The number of 16-bit characters that would have been + required to store the entire result string. This member + is only used when the structure is part of an rout or + inrout parameter, when it is an output value set by the + callee. The length of the returned wstring (including + the NULL terminator) after a call is the minimum of + dataLen and dataLenReq. + +See Also: + _cstring_t + _wchar_t + +======================================================================= +CONSTANTS DOCUMENTATION +======================================================================= + +TRUE + +Description: + TRUE is the boolean "true." + +Definition: + + #define TRUE 1 + +See Also: + FALSE + NULL + +======================================================================= + +FALSE + +Description: + FALSE is the boolean "false." + +Definition: + + #define FALSE 0 + +See Also: + NULL + TRUE + +======================================================================= + +NULL + +Description: + NULL is the null value, usually used to test a pointer. + +Definition: + + #define NULL 0 + +See Also: + FALSE + TRUE + +======================================================================= + +MIN_INT8 + +Description: + MIN_INT8 is the minimum signed 8-bit integer value. + +Definition: + + #define MIN_INT8 -128 + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MIN_INT16 + +Description: + MIN_INT16 is the minimum signed 16-bit integer value + +Definition: + + #define MIN_INT16 -32768 + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MIN_INT32 + +Description: + MIN_INT32 is the minimum signed 32-bit integer value. + +Definition: + + #define MIN_INT32 (~0x7fffffff) + +Comments: + Brew MP uses (~0x7fffffff), because -2147483648 is treated as unsigned by compilers. + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT64 + +======================================================================= + +MIN_INT64 + +Description: + MIN_INT64 is the minimum signed 64-bit integer value. + +Definition: + + #define MIN_INT64 (~0x7fffffffffffffffll) + +Comments: + Brew MP uses (~0x7fffffffffffffffll), because -9223372036854775808 is + treated as unsigned by compilers. + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + +======================================================================= + +MAX_INT8 + +Description: + MAX_INT8 is the maximum signed 8-bit integer value + +Definition: + + #define MAX_INT8 127 + +See Also: + MAX_AECHAR + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_INT16 + +Description: + MAX_INT16 is the maximum signed 16-bit integer value. + +Definition: + + #define MAX_INT16 32767 + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_INT32 + +Description: + MAX_INT32 is the maximum signed 32-bit integer value. + +Definition: + + #define MAX_INT32 2147483647 + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_INT64 + +Description: + MAX_INT64 is the maximum signed 64-bit integer value. + +Definition: + + #define MAX_INT64 9223372036854775807ll + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_UINT8 + +Description: + MAX_UINT8 is the maximum unsigned 8-bit integer value. + +Definition: + + #define MAX_UINT8 255 + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_UINT16 + +Description: + MAX_UINT16 is the maximum unsigned 16-bit integer value. + +Definition: + + #define MAX_UINT16 65535 + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT32 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_UINT32 + +Description: + MAX_UINT32 is the maximum unsigned 32-bit integer value. + +Definition: + + #define MAX_UINT32 4294967295u + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT64 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_UINT64 + +Description: + MAX_UINT64 is the maximum unsigned 64-bit integer value. + +Definition: + + #define MAX_UINT64 18446744073709551615ull + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MIN_AECHAR + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MIN_AECHAR + +Description: + MIN_AECHAR is the minimum AECHAR value. + +Definition: + + #define MIN_AECHAR 0 + +See Also: + MAX_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= + +MAX_AECHAR + +Description: + MAX_AECHAR is the maximum AECHAR value. + +Definition: + + #define MAX_AECHAR 65535 + +See Also: + MIN_AECHAR + MAX_INT8 + MAX_INT16 + MAX_INT32 + MAX_INT64 + MAX_UINT8 + MAX_UINT16 + MAX_UINT32 + MAX_UINT64 + MIN_INT8 + MIN_INT16 + MIN_INT32 + MIN_INT64 + +======================================================================= +MACROS DOCUMENTATION +======================================================================= + +__STR__() + +Description: + The __STR__() makes a token into a string, used to string-ize things already + defined. + +Definition: + + #define __STR__(x) #x + +Parameters: + x: token to make into a string + +See Also: + __TOSTR__() + __FILE_LINE__ + +======================================================================= + +__TOSTR__() + +Description: + The __TOSTR__() makes a token's value into a string, used to string-ize things + already defined, used with __STR__. + +Definition: + + #define __TOSTR__(x) __STR__(x) + +Parameters: + x: token to evaluate and string-ize + +Evaluation Value: + the token's replacement as a string + +See Also: + __FILE_LINE__ + __STR__() + +======================================================================= + +__FILE_LINE__ + +Description: + The compiler's __FILE__ (a string) and __LINE__ (an integer) are pasted + together as a single string with a ":" between. + +Definition: + + #define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__) + +Evaluation Value: + __FILE__":""__LINE__" + +See Also: + __STR__() + __TOSTR__() + +======================================================================= +*/ + +#endif /* #ifndef AEESTDDEF_H */ + diff --git a/inc/AEEStdErr.h b/inc/AEEStdErr.h new file mode 100644 index 0000000..638410d --- /dev/null +++ b/inc/AEEStdErr.h @@ -0,0 +1,356 @@ +/** + * 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 AEESTDERR_H +#define AEESTDERR_H + +// +// Basic Error Codes +// +// +#define AEE_SUCCESS 0 ///< No error +#define AEE_EUNKNOWN -1 /// Unknown error (should not use this) +#define AEE_EOFFSET 0x00000000 +#define AEE_EFAILED (AEE_EOFFSET + 0x001) ///< General failure +#define AEE_ENOMEMORY (AEE_EOFFSET + 0x002) ///< Insufficient RAM +#define AEE_ECLASSNOTSUPPORT (AEE_EOFFSET + 0x003) ///< Specified class unsupported +#define AEE_EVERSIONNOTSUPPORT (AEE_EOFFSET + 0x004) ///< Version not supported +#define AEE_EALREADYLOADED (AEE_EOFFSET + 0x005) ///< Object already loaded +#define AEE_EUNABLETOLOAD (AEE_EOFFSET + 0x006) ///< Unable to load object/applet +#define AEE_EUNABLETOUNLOAD (AEE_EOFFSET + 0x007) ///< Unable to unload + ///< object/applet +#define AEE_EALARMPENDING (AEE_EOFFSET + 0x008) ///< Alarm is pending +#define AEE_EINVALIDTIME (AEE_EOFFSET + 0x009) ///< Invalid time +#define AEE_EBADCLASS (AEE_EOFFSET + 0x00A) ///< NULL class object +#define AEE_EBADMETRIC (AEE_EOFFSET + 0x00B) ///< Invalid metric specified +#define AEE_EEXPIRED (AEE_EOFFSET + 0x00C) ///< App/Component Expired +#define AEE_EBADSTATE (AEE_EOFFSET + 0x00D) ///< Invalid state +#define AEE_EBADPARM (AEE_EOFFSET + 0x00E) ///< Invalid parameter +#define AEE_ESCHEMENOTSUPPORTED (AEE_EOFFSET + 0x00F) ///< Invalid URL scheme +#define AEE_EBADITEM (AEE_EOFFSET + 0x010) ///< Invalid item +#define AEE_EINVALIDFORMAT (AEE_EOFFSET + 0x011) ///< Invalid format +#define AEE_EINCOMPLETEITEM (AEE_EOFFSET + 0x012) ///< Incomplete item +#define AEE_ENOPERSISTMEMORY (AEE_EOFFSET + 0x013) ///< Insufficient flash +#define AEE_EUNSUPPORTED (AEE_EOFFSET + 0x014) ///< API is not supported +#define AEE_EPRIVLEVEL (AEE_EOFFSET + 0x015) ///< Privileges are insufficient + ///< for this operation +#define AEE_ERESOURCENOTFOUND (AEE_EOFFSET + 0x016) ///< Unable to find specified + ///< resource +#define AEE_EREENTERED (AEE_EOFFSET + 0x017) ///< Non re-entrant API + ///< re-entered +#define AEE_EBADTASK (AEE_EOFFSET + 0x018) ///< API called in wrong task + ///< context +#define AEE_EALLOCATED (AEE_EOFFSET + 0x019) ///< App/Module left memory + ///< allocated when released. +#define AEE_EALREADY (AEE_EOFFSET + 0x01A) ///< Operation is already in + ///< progress +#define AEE_EADSAUTHBAD (AEE_EOFFSET + 0x01B) ///< ADS mutual authorization + ///< failed +#define AEE_ENEEDSERVICEPROG (AEE_EOFFSET + 0x01C) ///< Need service programming +#define AEE_EMEMPTR (AEE_EOFFSET + 0x01D) ///< bad memory pointer +#define AEE_EHEAP (AEE_EOFFSET + 0x01E) ///< heap corruption +#define AEE_EIDLE (AEE_EOFFSET + 0x01F) ///< Context (system, interface, + ///< etc.) is idle +#define AEE_EITEMBUSY (AEE_EOFFSET + 0x020) ///< Context (system, interface, + ///< etc.) is busy +#define AEE_EBADSID (AEE_EOFFSET + 0x021) ///< Invalid subscriber ID +#define AEE_ENOTYPE (AEE_EOFFSET + 0x022) ///< No type detected/found +#define AEE_ENEEDMORE (AEE_EOFFSET + 0x023) ///< Need more data/info +#define AEE_EADSCAPS (AEE_EOFFSET + 0x024) ///< ADS Capabilities do not + ///< match those required for + ///< phone +#define AEE_EBADSHUTDOWN (AEE_EOFFSET + 0x025) ///< App failed to close properly +#define AEE_EBUFFERTOOSMALL (AEE_EOFFSET + 0x026) ///< Destination buffer given is + ///< too small +#define AEE_ENOSUCH (AEE_EOFFSET + 0x027) ///< No such name, port, socket + ///< or service exists or is + ///< valid +#define AEE_EACKPENDING (AEE_EOFFSET + 0x028) ///< ACK pending on application +#define AEE_ENOTOWNER (AEE_EOFFSET + 0x029) ///< Not an owner authorized to + ///< perform the operation +#define AEE_EINVALIDITEM (AEE_EOFFSET + 0x02A) ///< Current item is invalid +#define AEE_ENOTALLOWED (AEE_EOFFSET + 0x02B) ///< Not allowed to perform the + ///< operation +#define AEE_EBADHANDLE (AEE_EOFFSET + 0x02C) ///< Invalid handle +#define AEE_EOUTOFHANDLES (AEE_EOFFSET + 0x02D) ///< Out of handles +#define AEE_EINTERRUPTED (AEE_EOFFSET + 0x02E) ///< Waitable call is interrupted +#define AEE_ENOMORE (AEE_EOFFSET + 0x02F) ///< No more items available -- + ///< reached end +#define AEE_ECPUEXCEPTION (AEE_EOFFSET + 0x030) ///< A CPU exception occurred +#define AEE_EREADONLY (AEE_EOFFSET + 0x031) ///< Cannot change read-only + ///< object or parameter + +#define AEE_ECONNRESET 104 ///< Connection reset by peer +#define AEE_EWOULDBLOCK 516 ///< Operation would block if not + ///< non-blocking; wait and try + ///< again + +//Error code for sigverify +#define AEE_EUNSIGNEDMOD 4096 /// 0x1000 test-sig not found, Unsigned shared object +#define AEE_EINVALIDHASH 8192 /// 0x2000 test-sig not found, Invalid hash object + +#define AEE_EINVALIDMSG (AEE_EOFFSET + 0x032) /// Invalid SMD message from APPS +#define AEE_EINVALIDTHREAD (AEE_EOFFSET + 0x033) /// Invalid thread +#define AEE_EINVALIDPROCESS (AEE_EOFFSET + 0x034) /// Invalid Process +#define AEE_EINVALIDFILENAME (AEE_EOFFSET + 0x035) /// Invalid filename +#define AEE_EINVALIDDIGESTSIZE (AEE_EOFFSET + 0x036) /// Invalid digest size +#define AEE_EINVALIDSEGS (AEE_EOFFSET + 0x037) /// Invalid segments +#define AEE_EINVALIDSIGNATURE (AEE_EOFFSET + 0x038) /// Invalid signature +#define AEE_EINVALIDDOMAIN (AEE_EOFFSET + 0x039) /// Invalid domain +#define AEE_EINVALIDFD (AEE_EOFFSET + 0x03A) /// Invalid file descriptor +#define AEE_EINVALIDDEVICE (AEE_EOFFSET + 0x03B) /// Invalid Device +#define AEE_EINVALIDMODE (AEE_EOFFSET + 0x03C) /// Invalid Mode +#define AEE_EINVALIDPROCNAME (AEE_EOFFSET + 0x03D) /// Invalid Process name +#define AEE_ENOSUCHMOD (AEE_EOFFSET + 0x03E) /// No such module +#define AEE_ENOSUCHINSTANCE (AEE_EOFFSET + 0x03F) /// No instance in the list lookup +#define AEE_ENOSUCHTHREAD (AEE_EOFFSET + 0x040) /// No such thread +#define AEE_ENOSUCHPROCESS (AEE_EOFFSET + 0x041) /// No such process +#define AEE_ENOSUCHSYMBOL (AEE_EOFFSET + 0x042) /// No such symbol +#define AEE_ENOSUCHDEVICE (AEE_EOFFSET + 0x043) /// No such device +#define AEE_ENOSUCHPROP (AEE_EOFFSET + 0x044) /// No such dal property +#define AEE_ENOSUCHFILE (AEE_EOFFSET + 0x045) /// No such file +#define AEE_ENOSUCHHANDLE (AEE_EOFFSET + 0x046) /// No such handle +#define AEE_ENOSUCHSTREAM (AEE_EOFFSET + 0x047) /// No such stream +#define AEE_ENOSUCHMAP (AEE_EOFFSET + 0x048) /// No such Map +#define AEE_ENOSUCHREGISTER (AEE_EOFFSET + 0x049) /// No such register +#define AEE_ENOSUCHCLIENT (AEE_EOFFSET + 0x04A) /// No such QDI client +#define AEE_EBADDOMAIN (AEE_EOFFSET + 0x04B) /// Bad domain (not initialized) +#define AEE_EBADOFFSET (AEE_EOFFSET + 0x04C) /// Bad buffer/page/heap offset +#define AEE_EBADSIZE (AEE_EOFFSET + 0x04D) /// Bad buffer/page/heap size +#define AEE_EBADPERMS (AEE_EOFFSET + 0x04E) /// Bad FILE/MAP/MEM permissions +#define AEE_EBADFD (AEE_EOFFSET + 0x04F) /// Bad file descriptor +#define AEE_EBADPID (AEE_EOFFSET + 0x050) /// Bad PID from HLOS +#define AEE_EBADTID (AEE_EOFFSET + 0x051) /// Bad TID +#define AEE_EBADELF (AEE_EOFFSET + 0x052) /// Bad elf file +#define AEE_EBADASID (AEE_EOFFSET + 0x053) /// Bad asid +#define AEE_EBADCONTEXT (AEE_EOFFSET + 0x054) /// Bad context +#define AEE_EBADMEMALIGN (AEE_EOFFSET + 0x055) /// Bad memory alignment +#define AEE_EIOCTL (AEE_EOFFSET + 0x056) /// ioctl error +#define AEE_EFOPEN (AEE_EOFFSET + 0x057) /// file open error +#define AEE_EFGETS (AEE_EOFFSET + 0x058) /// file get string error +#define AEE_EFFLUSH (AEE_EOFFSET + 0x059) /// file flush error +#define AEE_EFCLOSE (AEE_EOFFSET + 0x05A) /// file close error +#define AEE_EEOF (AEE_EOFFSET + 0x05B) /// File EOF reached +#define AEE_EFREAD (AEE_EOFFSET + 0x05C) /// file read failed +#define AEE_EFWRITE (AEE_EOFFSET + 0x05D) /// file write failed +#define AEE_EFGETPOS (AEE_EOFFSET + 0x05E) /// file get position failed +#define AEE_EFSETPOS (AEE_EOFFSET + 0x05F) /// file set position failed +#define AEE_EFTELL (AEE_EOFFSET + 0x060) /// file tell position failed +#define AEE_EFSEEK (AEE_EOFFSET + 0x061) /// file seek failed +#define AEE_EFLEN (AEE_EOFFSET + 0x062) /// file len failed +#define AEE_EGETENV (AEE_EOFFSET + 0x063) /// get enviroment failed +#define AEE_ESETENV (AEE_EOFFSET + 0x064) /// set enviroment failed +#define AEE_EMMAP (AEE_EOFFSET + 0x065) /// mmap failed +#define AEE_EIONMAP (AEE_EOFFSET + 0x066) /// ion map failed +#define AEE_EIONALLOC (AEE_EOFFSET + 0x067) /// ion alloc failed +#define AEE_ENORPCMEMORY (AEE_EOFFSET + 0x068) /// ION memory allocation failed +#define AEE_ENOROOTOFTRUST (AEE_EOFFSET + 0x069) /// No root of trust for sigverify +#define AEE_ENOTLOCKED (AEE_EOFFSET + 0x06A) /// Unlock failed, not locked before +#define AEE_ENOTINITIALIZED (AEE_EOFFSET + 0x06B) /// Not initialized +#define AEE_EUNSUPPORTEDAPI (AEE_EOFFSET + 0x06C) /// unsupported API +#define AEE_EUNPACK (AEE_EOFFSET + 0x06D) /// unpacking command failed +#define AEE_EPOLL (AEE_EOFFSET + 0x06E) /// error while polling for event +#define AEE_EEVENTREAD (AEE_EOFFSET + 0x06F) /// event read failed +#define AEE_EMAXBUFS (AEE_EOFFSET + 0x070) /// Maximum buffers +#define AEE_EINVARGS (AEE_EOFFSET + 0x071) /// Invalid Arguments + +#define AEE_ESMD_OFFSET (AEE_EOFFSET + 0x100) /// SMD errors offset +#define AEE_ESMDBADPACKET (AEE_EOFFSET + 0x101) /// SMD invalid packet size +#define AEE_ESMDALREADYOPEN (AEE_EOFFSET + 0x102) /// SMD port is already open +#define AEE_ESMDOPENFAILED (AEE_EOFFSET + 0x103) /// SMD port open failed + +#define AEE_EDAL_OFFSET (AEE_EOFFSET + 0x120) /// Dal error offset +#define AEE_EDALDEVATTACH (AEE_EOFFSET + 0x121) /// DAL attach error +#define AEE_EDALINTREGISTER (AEE_EOFFSET + 0x122) /// DAL interrupt register error +#define AEE_EDALINTUNREGISTER (AEE_EOFFSET + 0x123) /// Dal interrupt unregister error +#define AEE_EDALGETPROP (AEE_EOFFSET + 0x124) /// Dal get property +#define AEE_EDALGETVAL (AEE_EOFFSET + 0x125) /// Dal get property value + +#define AEE_EQURT_OFFSET (AEE_EOFFSET + 0x140) /// QURT error offset +#define AEE_EQURTREGIONCREATE (AEE_EOFFSET + 0x141) /// QURT region create failed +#define AEE_EQURTCACHECLEAN (AEE_EOFFSET + 0x142) /// QURT cache clean failed +#define AEE_EQURTREGIONGETATTR (AEE_EOFFSET + 0x143) /// QURT region get attribute failed +#define AEE_EQURTBADREGIONPERMS (AEE_EOFFSET + 0x144) /// QURT bad permissions for region +#define AEE_EQURTMEMPOOLADD (AEE_EOFFSET + 0x145) /// QURT Add to memory pool failed +#define AEE_EQURTREGISTERDEV (AEE_EOFFSET + 0x146) /// QURT register device failed +#define AEE_EQURTMEMPOOLCREATE (AEE_EOFFSET + 0x147) /// QURT create memory pool failed +#define AEE_EQURTGETVA (AEE_EOFFSET + 0x148) /// QURT get VA failed +#define AEE_EQURTREGIONDELETE (AEE_EOFFSET + 0x149) /// QURT region delete failed +#define AEE_EQURTMEMPOOLATTACH (AEE_EOFFSET + 0x14A) /// QURT memory pool attach failed +#define AEE_EQURTTHREADCREATE (AEE_EOFFSET + 0x14B) /// QURT thread create failed +#define AEE_EQURTCOPYTOUSER (AEE_EOFFSET + 0x14C) /// QURT copy to user memory failed +#define AEE_EQURTMEMMAPCREATE (AEE_EOFFSET + 0x14D) /// QURT map create failed +#define AEE_EQURTINVHANDLE (AEE_EOFFSET + 0x14E) /// QURT Invalid client handle +#define AEE_EQURTBADASID (AEE_EOFFSET + 0x14F) /// QURT Bad ASIC from QURT +#define AEE_EQURTOPENFAILED (AEE_EOFFSET + 0x150) /// QURT QDI open failed +#define AEE_EQURTCOPYFROMUSER (AEE_EOFFSET + 0x151) /// QURT Copy from user failed +#define AEE_EQURTLINELOCK (AEE_EOFFSET + 0x152) /// QURT Line lock failed +#define AEE_EQURTQDIDEFMETHOD (AEE_EOFFSET + 0x153) /// QURT QDI default method failed + +#define AEE_EMMPM_OFFSET (AEE_EOFFSET + 0x170) /// MMPM errors offset +#define AEE_EMMPMREQUEST (AEE_EOFFSET + 0x171) /// MMPM Power request to failed +#define AEE_EMMPMRELEASE (AEE_EOFFSET + 0x172) /// MMPM Release request failed +#define AEE_EMMPMSETPARAM (AEE_EOFFSET + 0x173) /// MMPM set param request failed +#define AEE_EMMPMREGISTER (AEE_EOFFSET + 0x174) /// MMPM Register request failed +#define AEE_EMMPMGETINFO (AEE_EOFFSET + 0x175) /// MMPM Get info failed + + +/* +============================================================================ + ERRORS DOCUMENTATION +============================================================================== + +Error Codes + +Description: +This topic lists the categories of error codes that Brew MP returns. The topic for each +category of error code includes the name of each error, the code that is associated with +the error, and a description of the error. + +===H2> +List of Error Code Types +===/H2> +===p> +The categories of error codes include: ~ +~ + +AddrBook error codes ~ +AddrInfo error codes ~ +AEE_IS_REMOTE_ERR(): ~ +AEE_IS_REMOTE_ERR_PRE(): ~ +Basic AEE Error Codes ~ +Database error codes ~ +dbc Error Codes ~ +DNS Resolver error codes ~ +File error codes ~ +FS AEE Error Codes ~ +ICamera error codes ~ +ICMP error codes ~ +ILicenseSystem Error Codes ~ +Indeterminate errors: (transport failure) ~ +ISQL Error Codes ~ +ISVGDOM Error Codes: ~ +ISSL error codes ~ +IX509Chain error codes ~ +ModCollector Errors ~ +ModInstallerCntx Errors ~ +ModMover Errors ~ +Multimedia error codes ~ +Network AEE error codes ~ +Network subsystem error codes ~ +pim_IMessageStore Error Codes ~ +pim_IRecordStore Error Codes ~ +Port AEE Error Codes ~ +PosDet error codes ~ +Post-invocation errors: (remote errors) ~ +Pre-invocation errors: (remote errors) ~ +QoS error codes ~ +Remote error codes: ~ +SSL error codes ~ +VOCODER error codes ~ +VolumeDB Errors ~ +Web error codes ~ + +* + +================================================================== +Basic AEE Error Codes + +Description: +This section lists the set of basic AEE errors returned, the codes associated +with the errors, and descriptions of the errors. + +Definition: + +Error Code Description + +AEE_SUCCESS 0 operation Successful +AEE_EFAILED 1 general failure +AEE_ENOMEMORY 2 insufficient RAM +AEE_ECLASSNOTSUPPORT 3 specified class unsupported +AEE_EVERSIONNOTSUPPORT 4 version not supported +AEE_EALREADYLOADED 5 object already loaded +AEE_EUNABLETOLOAD 6 unable to load object/applet +AEE_EUNABLETOUNLOAD 7 unable to unload object/applet +AEE_EALARMPENDING 8 alarm is pending +AEE_EINVALIDTIME 9 invalid time +AEE_EBADCLASS 10 NULL class object +AEE_EBADMETRIC 11 invalid metric specified +AEE_EEXPIRED 12 Application/Component Expired +AEE_EBADSTATE 13 invalid state +AEE_EBADPARM 14 invalid parameter +AEE_ESCHEMENOTSUPPORTED 15 invalid URL scheme +AEE_EBADITEM 16 invalid item +AEE_EINVALIDFORMAT 17 invalid format +AEE_EINCOMPLETEITEM 18 incomplete item +AEE_ENOPERSISTMEMORY 19 insufficient flash +AEE_EUNSUPPORTED 20 API is not supported +AEE_EPRIVLEVEL 21 application privileges are insufficient for this operation +AEE_ERESOURCENOTFOUND 22 unable to find specified resource +AEE_EREENTERED 23 non re-entrant API re-entered +AEE_EBADTASK 24 API called in wrong task context +AEE_EALLOCATED 25 Application/Module left memory allocated when released +AEE_EALREADY 26 operation is already in progress +AEE_EADSAUTHBAD 27 ADS mutual authorization failed +AEE_ENEEDSERVICEPROG 28 need service programming +AEE_EMEMPTR 29 bad memory pointer +AEE_EHEAP 30 heap corruption +AEE_EIDLE 31 context (system, interface, etc.) is idle +AEE_EITEMBUSY 32 context (system, interface, etc.) is busy +AEE_EBADSID 33 invalid subscriber ID +AEE_ENOTYPE 34 no type detected/found +AEE_ENEEDMORE 35 need more data/info +AEE_EADSCAPS 36 capabilities do not match those required +AEE_EBADSHUTDOWN 37 application failed to close properly +AEE_EBUFFERTOOSMALL 38 destination buffer given is too small +AEE_ENOSUCH 39 no such name/port/socket/service exists or valid +AEE_EACKPENDING 40 ACK pending on application +AEE_ENOTOWNER 41 not an owner authorized to perform the operation +AEE_EINVALIDITEM 42 current item is invalid +AEE_ENOTALLOWED 43 not allowed to perform the operation +AEE_EBADHANDLE 44 invalid handle +AEE_EOUTOFHANDLES 45 out of handles +AEE_EINTERRUPTED 46 waitable call is interrupted +AEE_ENOMORE 47 no more items available -- reached end +AEE_ECPUEXCEPTION 48 a CPU exception occurred +AEE_EREADONLY 49 cannot change read-only object or parameter +AEE_ECONNRESET 104 connection reset by peer +AEE_EWOULDBLOCK 516 operation would block if not non-blocking; wait and try again + +Comments: +These Brew MP error codes have an up-to-date naming convention, and replace older BREW error +codes that use a naming convention that did not include the "AEE_" prefix. + +See Also: + Error Codes + +================================================================== +*/ +#endif /* #ifndef AEESTDERR_H */ + diff --git a/inc/AEEVaList.h b/inc/AEEVaList.h new file mode 100644 index 0000000..1ed8476 --- /dev/null +++ b/inc/AEEVaList.h @@ -0,0 +1,112 @@ +/** + * 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 AEEVALIST_H +#define AEEVALIST_H + +#if !defined(__clang__) && (defined(__ARMCC_VERSION) || (defined(__GNUC__) && defined(__arm__))) + + + +#if (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 200000 && !defined(__APCS_ADSABI)) || \ + (defined(__GNUC__) && defined(__arm__) && defined(__ARM_EABI__)) + +# define __AEEVA_ATPCS 0 + +#else + +# define __AEEVA_ATPCS 1 + +#endif + +typedef void* AEEVaList; + +#define __AEEVA_ARGALIGN(t) (((char*)(&((struct{char c;t x;}*)1)->x))-((char*)1)) +#define __AEEVA_ARGSIZE(t) ((sizeof(t)+sizeof(int)-1) & ~(sizeof(int)-1)) + +static __inline void __cpy(char*d, const char*s, int len) +{ + while (len-- > 0) *d++ = *s++; +} + +static __inline AEEVaList __AEEVa_Arg(AEEVaList args, void* pv, int nVSize, + int nArgSize, int nArgAlign) +{ + int nArgs = (int)args & ~1; + char* pcArgs = (char*)args; + int bATPCS = (int)args & 1; + int nArgsOffset = 0; + int nVOffset = 0; + + if (!bATPCS) { /* caller was compiled with AAPCS */ + + if (nArgAlign > (int)sizeof(int)) { + nArgAlign--; /* make a mask */ + pcArgs += ((nArgs + nArgAlign) & (int)~(unsigned)nArgAlign) - nArgs; + /* move pv to next alignment */ + } + } + +#if defined(AEE_BIGENDIAN) + if (nArgSize < (int)sizeof(int)) { + nArgsOffset = (int)sizeof(int) - nArgSize; + } + nVOffset = nVSize - nArgSize; +#else + (void)nVSize; +#endif /* AEE_BIGENDIAN */ + + __cpy((char*)pv + nVOffset, (pcArgs - bATPCS) + nArgsOffset, nArgSize); + + /* round up */ + nArgSize = (nArgSize+(int)sizeof(int)-1) & ~((int)sizeof(int)-1); + + return pcArgs + nArgSize; /* increment va */ +} + +#define AEEVA_START(va,v) ((va) = (char*)&(v) + __AEEVA_ARGSIZE(v) + __AEEVA_ATPCS) +#define AEEVA_ARG(va,v,t) ((void)((va) = __AEEVa_Arg(va,&v,sizeof(v),sizeof(t),__AEEVA_ARGALIGN(t)))) +#define AEEVA_END(va) ((va) = (AEEVaList)0) +#define AEEVA_COPY(dest, src) ((void)((dest) = (src))) + +#else /* !defined(__clang__) && (defined(__ARMCC_VERSION) || (defined(__GNUC__) && defined(__arm__))) */ + +#include <stdarg.h> + +typedef va_list AEEVaList; + +#define AEEVA_START(va,v) (va_start((va), (v))) +#define AEEVA_ARG(va,v,t) ((v) = va_arg((va),t)) +#define AEEVA_END(va) (va_end((va))) +#define AEEVA_COPY(dest, src) (va_copy((dest),(src))) + +#endif/* !defined(__clang__) && (defined(__ARMCC_VERSION) || (defined(__GNUC__) && defined(__arm__))) */ + +#endif /* #ifndef AEEVALIST_H */ + diff --git a/inc/AEEatomic.h b/inc/AEEatomic.h new file mode 100644 index 0000000..c2f28b4 --- /dev/null +++ b/inc/AEEatomic.h @@ -0,0 +1,198 @@ +/** + * 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 AEEATOMIC_H +#define AEEATOMIC_H +/* +======================================================================= + +FILE: AEEatomic.h + +SERVICES: atomic + +DESCRIPTION: Fast Atomic ops + +======================================================================= +*/ + +#include "AEEStdDef.h" + +#ifdef __cplusplus +extern "C" { +#endif /* #ifdef __cplusplus */ + +uint32 atomic_Add(uint32 * volatile puDest, int nAdd); +uint32 atomic_Exchange(uint32 * volatile puDest, uint32 uVal); +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare); +uint32 atomic_CompareOrAdd(uint32 * volatile puDest, uint32 uCompare, int nAdd); + +uint64 atomic_CompareAndExchange64(uint64 * volatile puDest, uint64 uExchange, uint64 uCompare); +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare); +#ifdef __cplusplus +} +#endif /* #ifdef __cplusplus */ + +/*===================================================================== +INTERFACE DOCUMENTATION +======================================================================= +atomic Interface + + The atomic interface provides fast "atomic" operations. The + operations are defined to be atomic with respect to each other. + +======================================================================= + +======================================================================= + +atomic_Add() + +Description: + + Performs an atomic sum operation. + +Prototype: + + uint32 atomic_Add(uint32* puDest, int nInc); + +Parameters: + puDest [in|out] : Points to unsigned number to add nInc and save + nInc : increment + +Return Value: + result. + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +atomic_Exchange() + +Description: + + Atomic exchange of 32bit value. Performs an atomic operation of : + write uVal to *puDest + return the previous value in *puDest + +Prototype: + + uint32 atomic_Exchange(uint32* puDest, uint32 uVal); + +Parameters: + puDest [in|out] : Points to unsigned number to be exchanged + uVal : new value to write. + +Return Value: + previous value at *puDest. + +Comments: + None + +Side Effects: + May cause exception if puDest is not a 32 bit aligned address. + +See Also: + None +======================================================================= + +atomic_CompareAndExchange() + +Description: + + Performs an atomic operation of : + if (*puDest == uCompare) { + *puDest = uExchange; + } + + returns the previous value in *puDest + +Prototype: + + uint32 atomic_CompareAndExchange(uint32 *puDest, uint32 uExchange, + uint32 uCompare); + +Parameters: + puDest [in|out] : Points to unsigned number. + uExchange : A new value to write to *puDest + uCompare : Comparand + +Return Value: + previous value at *puDest. + +Comments: + None + +Side Effects: + May cause exception if puDest is not a 32 bit aligned address. + +See Also: + None + +======================================================================= +atomic_CompareOrAdd() + +Description: + + Performs an atomic operation of : + if (*puDest != uCompare) { + *puDest += nAdd; + } + + returns the new value in *puDest + +Prototype: + + uint32 atomic_CompareOrAdd(uint32 *puDest, uint32 uCompare, int nAdd); + +Parameters: + puDest [in|out] : Points to unsigned number. + uCompare : Comparand + nAdd : Add to *puDest + +Return Value: + new value at *puDest. + +Comments: + None + +Side Effects: + May cause exception if puDest is not a 32 bit aligned address. + +See Also: + None +=======================================================================*/ + +#endif /* #ifndef AEEATOMIC_H */ + diff --git a/inc/AEEstd.h b/inc/AEEstd.h new file mode 100644 index 0000000..2c832e6 --- /dev/null +++ b/inc/AEEstd.h @@ -0,0 +1,2681 @@ +/** + * 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 AEESTD_H +#define AEESTD_H +/*==================================================================== + +DESCRIPTION: Standard library; general-purpose utility functions. + +====================================================================*/ +#include "AEEVaList.h" +#include "AEEStdDef.h" +#include "string.h" + +#define STD_CONSTRAIN( val, min, max ) (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val)) +#define STD_BETWEEN( val, minGE, maxLT ) \ + ( (unsigned long)((unsigned long)(val) - (unsigned long)(minGE)) < \ + (unsigned long)((unsigned long)(maxLT) - (unsigned long)(minGE)) ) +#define STD_ARRAY_SIZE(a) ((int)((sizeof((a))/sizeof((a)[0])))) +#define STD_ARRAY_MEMBER(p,a) (((p) >= (a)) && ((p) < ((a) + STD_ARRAY_SIZE(a)))) + +#define STD_SIZEOF(x) ((int)sizeof(x)) +#define STD_OFFSETOF(type,member) (((char*)(&((type*)1)->member))-((char*)1)) + +#define STD_RECOVER_REC(type,member,p) ((void)((p)-&(((type*)1)->member)),\ + (type*)(void*)(((char*)(void*)(p))-STD_OFFSETOF(type,member))) +#define STD_MIN(a,b) ((a)<(b)?(a):(b)) +#define STD_MAX(a,b) ((a)>(b)?(a):(b)) +//lint -emacro(545,STD_ZEROAT) +#define STD_ZEROAT(p) std_memset((p), 0, sizeof(*p)) + +#define _STD_BITS_PER(bits) (8*sizeof((bits)[0])) + +#define STD_BIT_SET(bits, ix) ((bits)[(ix)/_STD_BITS_PER((bits))] |= 0x1<<((ix) & (_STD_BITS_PER((bits))-1))) +#define STD_BIT_CLEAR(bits, ix) ((bits)[(ix)/_STD_BITS_PER((bits))] &= ~(0x1<<((ix) & (_STD_BITS_PER((bits))-1)))) +#define STD_BIT_TEST(bits, ix) ((bits)[(ix)/_STD_BITS_PER((bits))] & (0x1<<((ix) & (_STD_BITS_PER((bits))-1)))) + +// +// Error codes +// +#define STD_NODIGITS 1 +#define STD_NEGATIVE 2 +#define STD_OVERFLOW 3 +#define STD_BADPARAM 4 +#define STD_UNDERFLOW 5 + +//Compute string length using strlen +#define std_strlen strlen + +#ifdef __cplusplus +extern "C" { +#endif /* #ifdef __cplusplus */ + +//Version function +extern int std_getversion(char *pcDst, int nDestSize); + +//String functions +extern int std_strcmp(const char *s1, const char *s2); +extern int std_strncmp(const char *s1, const char *s2, int n); +extern int std_stricmp(const char *s1, const char *s2); +extern int std_strnicmp(const char *s1, const char *s2, int n); +extern int std_strlcpy(char *pcDst, const char *pszSrc, int nDestSize); +extern int std_strlcat(char *pcDst, const char *pszSrc, int nDestSize); +extern char * std_strstr(const char *pszString, const char *pszSearch); + +//Character functions +extern char std_tolower(char c); +extern char std_toupper(char c); + +// Mem functions +extern void * std_memset(void *p, int c, int nLen); +extern void * std_memmove(void *pTo, const void *cpFrom, int nLen); +extern int std_memscpy(void *dst, int dst_size, const void *src, int src_size); +extern int std_memsmove(void *dst, int dst_size, const void *src, int src_size); +extern int std_memcmp(const void *a, const void *b, int length); +extern void * std_memchr(const void* s, int c, int n); +extern void * std_memstr(const char* cpHaystack, const char* cpszNeedle, int nHaystackLen); +extern void * std_memrchr(const void* s, int c, int n); +extern void * std_memrchrbegin(const void* p, int c, int nLen); +extern void * std_memchrend(const void* cpcSrch, int c, int nLen); +extern void * std_memchrsend(const void *cpSrch, const char* cpszChars, int nLen); + +//Other String functions +extern char * std_strchr(const char* s, int c); +extern char * std_strchrs(const char* sSrch, const char *sChars); +extern char * std_strrchr(const char* s, int c); +extern char * std_strchrend(const char *cpszSrch, char c); +extern char * std_strchrsend(const char* s, const char* cpszSrch); +extern char * std_strends(const char* cpsz, const char* cpszSuffix); +extern char * std_striends(const char* cpsz, const char* cpszSuffix); +extern char * std_strbegins(const char* cpsz, const char* cpszPrefix); +extern char * std_stribegins(const char* cpsz, const char* cpszPrefix); +extern int std_strcspn(const char* s, const char* cpszSrch); +extern int std_strspn(const char* s, const char* cpszSrch); + +//Wide char string functions +extern int std_wstrlen(const AECHAR *s); +extern int std_wstrlcpy(AECHAR *pcDst, const AECHAR *pszSrc, int nDestSize); +extern int std_wstrlcat(AECHAR *pcDst, const AECHAR *pszSrc, int nDestSize); +extern int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen); +extern int std_wstrcmp(const AECHAR* s1, const AECHAR* s2); +extern AECHAR* std_wstrchr(const AECHAR* cpwszText, AECHAR ch); +extern AECHAR* std_wstrrchr(const AECHAR* cpwszText, AECHAR ch); + +//Path functions +extern int std_makepath(const char *cpszDir, + const char *cpszFile, + char *pszDest, int nDestSize); +extern char * std_splitpath(const char *cpszPath, const char *cpszDir); +extern char * std_cleanpath(char *pszPath); +extern char * std_basename(const char *pszPath); + +//Inet functions, number functions +extern unsigned int std_scanul(const char *pchBuf, int nRadix, + const char **ppchEnd, int *pnError); +extern uint64 std_scanull(const char *pchBuf, int nRadix, + const char **ppchEnd, int *pnError); +extern double std_scand(const char *pchBuf, const char **ppchEnd); + +// Rand functions +extern unsigned std_rand_next(unsigned uRand); +extern uint32 std_rand(uint32 uSeed, byte* pDest, int nSize); + + +// printf functions +extern int std_vstrlprintf(char *pszDest, int nDestSize, + const char *pszFmt, AEEVaList args); + +extern int std_strlprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); + +extern int std_vsnprintf(char *pszDest, int nDestSize, + const char *cpszFmt, AEEVaList args); + +extern int std_snprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); + +// endian swapping functions +extern int std_CopyLE(void *pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields); + +extern int std_CopyBE(void *pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields); + +// sorting utilities +extern void std_qsort(void* pElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +extern int std_bisect(const void* pElems, int nNumElems, int nElemWidth, + const void* pElem, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +extern void std_merge(void* vpDst, int nDst, + const void* vpA, int nA, + const void* vpB, int nB, + int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +extern int std_uniq(void* vpElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +#ifdef __cplusplus +} +#endif /* #ifdef __cplusplus */ + + +#define STD_SWAPS(us) \ + ((((us) & 0xff) << 8) + (((us) & 0xff00) >> 8)) + + +static __inline unsigned short std_swaps(unsigned short us) +{ + return STD_SWAPS(us); +} + +/* note, STD_SWAPL() requires that ul be an l-value, and destroyable. + this macro is not intended for use outside AEEstd.h */ +#define STD_SWAPL(ul) \ + (((ul) = (((ul) & 0x00ff00ff) << 8) | (((ul)>>8) & 0x00ff00ff)),(((ul) >> 16) | ((ul) << 16))) + +static __inline unsigned long std_swapl(unsigned long ul) +{ + return STD_SWAPL(ul); +} + +#ifdef AEE_BIGENDIAN +# define STD_HTONL(u) (u) +# define STD_HTONS(u) (u) +# define STD_HTOLEL(u) (STD_SWAPL(u)) +# define STD_HTOLES(u) (STD_SWAPS(u)) +#else +# define STD_HTONL(u) (STD_SWAPL(u)) +# define STD_HTONS(u) (STD_SWAPS(u)) +# define STD_HTOLEL(u) (u) +# define STD_HTOLES(u) (u) +#endif + +static __inline unsigned short std_letohs(unsigned short us) +{ + return STD_HTOLES(us); +} + +static __inline unsigned short std_htoles(unsigned short us) +{ + return STD_HTOLES(us); +} + +static __inline unsigned long std_letohl(unsigned long ul) +{ + return STD_HTOLEL(ul); +} + +static __inline unsigned long std_htolel(unsigned long ul) +{ + return STD_HTOLEL(ul); +} + +static __inline unsigned short std_ntohs(unsigned short us) +{ + return STD_HTONS(us); +} + +static __inline unsigned short std_htons(unsigned short us) +{ + return STD_HTONS(us); +} + +static __inline unsigned long std_ntohl(unsigned long ul) +{ + return STD_HTONL(ul); +} + +static __inline unsigned long std_htonl(unsigned long ul) +{ + return STD_HTONL(ul); +} + + +#undef STD_HTONL // private macro; not exported as a supported API +#undef STD_HTONS // private macro; not exported as a supported API +#undef STD_HTOLEL // private macro; not exported as a supported API +#undef STD_HTOLES // private macro; not exported as a supported API +#undef STD_SWAPS // private macro; not exported as a supported API +#undef STD_SWAPL // private macro; not exported as a supported API + + +/* +======================================================================= +MACROS DOCUMENTATION +======================================================================= + +STD_CONTSTRAIN() + +Description: + STD_CONTSTRAIN() constrains a number to be between two other numbers. + +Definition: + STD_CONSTRAIN( val, min, max ) \ + (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val)) + +Parameters: + val: number to constrain + min: number to stay greater than or equal to + max: number to stay less than or equal to + +Evaluation Value: + the constrained number + +======================================================================= + +STD_BETWEEN() + +Description: + STD_BETWEEN() tests whether a number is between two other numbers. + +Definition: + STD_BETWEEN( val, minGE, maxLT ) \ + ((unsigned)((unsigned)(val) - (unsigned)(minGE)) < \ + (unsigned)((unsigned)(maxLT) - (unsigned)(minGE))) + +Parameters: + val: value to test + minGE: lower bound + maxLT: upper bound + +Evaluation Value: + 1 if val >= minGE and val < maxLT + +======================================================================= + +STD_ARRAY_SIZE() + +Description: + STD_ARRAY_SIZE() gives the number of elements in a statically allocated array. + +Definition: + STD_ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) + +Parameters: + a: array to test + +Evaluation Value: + number of elements in a + +======================================================================= + +STD_ARRAY_MEMBER() + +Description: + STD_ARRAY_MEMBER() tests whether an item is a member of a statically allocated array. + +Definition: + STD_ARRAY_MEMBER(p,a) (((p) >= (a)) && ((p) < ((a) + STD_ARRAY_SIZE(a)))) + +Parameters: + p: item to test + a: array to check + +Evaluation Value: + 1 if p is in a + +======================================================================= + +STD_OFFSETOF() + +Description: + STD_OFFSETOF() gives the offset of member of a struct. + +Definition: + STD_OFFSETOF(type,member) (((char *)(&((type *)0)->member))-((char *)0)) + +Parameters: + type: structured type + member: name of member in the struct + +Evaluation Value: + offset of member (in bytes) in type + +======================================================================= + +STD_RECOVER_REC() + +Description: + STD_RECOVER_REC() provides a safe cast from a pointer to a member + of a struct to a pointer to the containing struct + +Definition: + STD_RECOVER_REC(type,member,p) ((type*)(((char*)(p))-STD_OFFSETOF(type,member))) + +Parameters: + type: structured type + member: name of member in the struct + p: pointer to the member of the struct + +Evaluation Value: + a pointer of type type to the containing struct + +======================================================================= + +STD_MIN() + +Description: + STD_MIN() finds the smaller of two values. + +Definition: + STD_MIN(a,b) ((a)<(b)?(a):(b)) + +Parameters: + a, b: values to compare + +Evaluation Value: + smaller of a and b + +======================================================================= + +STD_MAX() + +Description: + STD_MAX() finds the larger of two values. + +Definition: + STD_MAX(a,b) ((a)>(b)?(a):(b)) + +Parameters: + a, b: values to compare + +Evaluation Value: + larger of a and b + +======================================================================= + +STD_ZEROAT() + +Description: + STD_ZEROAT() zero-initializes the contents of a typed chunk of memory. + +Definition: + STD_ZEROAT(p) std_memset((p), 0, sizeof(*p)) + +Parameters: + p: the chunk to initialize + +Evaluation Value: + p + +======================================================================= + +STD_BIT_SET() + +Description: + STD_BIT_SET(bits, ix) sets the bit in the memory stored in bits at + index ix + +Parameters: + bits: the memory address holding the bits + ix: the index of the bit to set; + +======================================================================= + +STD_BIT_CLEAR() + +Description: + STD_BIT_CLEAR(bits, ix) clears the bit in the memory stored in bits + at index ix + +Parameters: + bits: the memory address holding the bits + ix: the index of the bit to clear + +======================================================================= + +STD_BIT_TEST() + +Description: + STD_BIT_TEST(bits, ix) returns the bit in the memory stored in bits + at index ix + +Parameters: + bits: the memory address holding the bits + ix: the index of the bit to test + +Evaluation Value: + 0x1 if set 0x0 if not set + +===================================================================== +INTERFACES DOCUMENTATION +======================================================================= + +std Interface + +Description: + This library provides a set of general-purpose utility functions. + Functionality may overlap that of a subset of the C standard library, but + this library differs in a few respects: + + - Functions are fully reentrant and avoid use of static variables. + + - The library can be supported consistently across all environments. + Compiler-supplied libraries sometimes behave inconsistently and are + unavailable in some environments. + + - Omits "unsafe" functions. C standard library includes many functions + that are best avoided entirely: strcpy, strcat, strtok, etc. + + +======================================================================= + +std_getversion() + +Description: + + The std_getversion() copies the stdlib version to pcDst. This function + takes the size of the destination buffer as an argument and guarantees + to zero-terminate the result and not to overflow the nDestSize size. + + This function copies up to size-1 characters from the stdlib version + string to pcDest and NUL-terminates the pcDest string. + +Prototype: + int std_getversion(char *pcDst, int nDestSize) + + +Parameters: + pcDst : Destination string + nDestSize: Size of the destination buffer in bytes + +Return Value: + + Returns the length of the version string (in characters). + +======================================================================= + +std_strlen() + +Description: + The std_strlen() computes the length of the given string. + +Prototype: + int std_strlen(const char *cpszStr) + +Parameters: + cpszStr : String whose length will be computed + +Return Value: + Length of the string in characters that precede the terminating NULL character. + +======================================================================= + +std_strcmp() + +Description: + The std_strcmp() compares two NUL-terminated character strings. + Comparison is strictly by byte values with no character set + interpretation. + +Prototype: + + int std_strcmp(const char *s1, const char *s2); + +Parameters: + s1, s2: strings to compare + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_wstrcmp + +======================================================================= + +std_strncmp() + +Description: + The std_strncmp() compares at most n bytes of two NUL-terminated character strings. + +Prototype: + + int std_strncmp(const char *s1, const char *s2, int n); + +Parameters: + s1, s2: strings to compare + n: maximum number of bytes to compare. if either s1 or s2 is + shorter than n, the function terminates there + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_wstrncmp + +======================================================================= + +std_stricmp() + +Description: + The std_stricmp() compares two NUL-terminated character strings, case-folding any + ASCII characters. + +Prototype: + + int std_stricmp(const char *s1, const char *s2); + +Parameters: + s1, s2: strings to compare + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +======================================================================= + +std_strnicmp() + +Description: + The std_strnicmp() compares at most n bytes of 2 NUL-terminated character strings, + case-folding any ASCII characters. + +Prototype: + + int std_strnicmp(const char *s1, const char *s2, int n); + +Parameters: + s1, s2: strings to compare + n: maximum number of bytes to compare. if either s1 or s2 is + shorter than n, the function terminates there + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +======================================================================= + +std_strlcpy() + +Description: + + The std_strlcpy() copies pszSrc string to the pcDst. It is a safer + alternative to strcpy() or strncpy(). This function takes the size of the + destination buffer as an argument and guarantees to NUL-terminate the + result and not to overflow the nDestSize size. + + This function copies up to nDestSize-1 characters from the pszSrc string + to pcDest and NUL-terminates the pcDest string. + +Prototype: + int std_strlcpy(char *pcDst, const char *pszSrc, int nDestSize) + +Parameters: + pcDst : Destination string + pcSrc : Source string + nDestSize: Size of the destination buffer in bytes + +Return Value: + + Returns the length of the string (in characters) it tried to create, + which is same as length of pszSrc. + + Example: + + { + char buf[64]; + if (std_strlcpy(buf, file_name, STD_ARRAY_SIZE(buf) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + +Comment: + + Unlike strlcpy, std_strlcpy accepts an integer size and does nothing when a + negative value is passed. When passing valid sizes for objects on our + supported platforms, this should not result in any observed difference. + However, calling strlcpy() with UINT_MAX will result in the entire source + string being copied, whereas std_strlcpy() will do nothing. Passing INT_MAX + to str_strlcpy() will achieve the same result (although both these cases are + bad practice since they defeat bounds checking). + + +======================================================================= + +std_strlcat() + +Description: + + The std_strlcat() function concatenates a string to a string already + residing in a buffer. It is a safer alternative to strcat() or strncat(). + This function takes the size of the destination buffer as an argument and + guarantees not to create an improperly terminated string and not to + overflow the nDestSize size. + + This function appends pszSrc to pcDst, copying at most nDestSize minus + the length of the string in pcDest minus 1 bytes, always NUL-terminating + the result. + + For compatibility with "strlcat()", std_strlcat() does *not* zero-terminate + the destination buffer in cases where the buffer lacks termination on entry + to the function. Do not rely on std_strlcat() to zero-terminate a buffer + that is not already zero-terminated; instead ensure that the buffer is + properly initialized using std_strlcpy() or some other means. + +Prototype: + + int std_strlcat(char *pcDst, const char *pszSrc, int nDestSize) + +Parameters: + + pcDst : Destination string + pcSrc : Source string + nDestSize: Size of the destination buffer in bytes + +Return Value: + + Returns the length of the string (in characters) it tried to create, + which is same as length of pszSrc plus the length of pszDest. + + Example: + + { + char buf[64]; + if (std_strlcat(buf, file_name, STD_ARRAY_SIZE(buf) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + + +======================================================================= + +std_strstr() + +Description: + The std_strstr() finds the first occurrence of a substring in a string. + +Prototype: + + char * std_strstr(const char *pszString, const char *pszSearch); + +Parameters: + pszString: string to search + pszSearch: sub string to search for + +Return Value: + A pointer to the first character in the first occurrence of the substring if found, NULL otherwise + +======================================================================= + +std_tolower() + +Description: + The std_tolower() converts an uppercase letter to the corresponding + lowercase letter. + +Prototype: + char std_tolower(char c); + +Parameters: + c: A character. + +Return Value: + the corresponding lowercase letter if c is an ASCII character whose + value is representable as an uppercase letter, else the same character + c is returned. + +======================================================================= + +std_toupper() + +Description: + The std_toupper() converts an lowercase letter to the corresponding + uppercase letter. + +Prototype: + char std_toupper(char c); + +Parameters: + c: is a character. + +Return Value: + The corresponding uppercase letter if c is an ASCII character whose + value is representable as an lowercase letter; else the same character + c is returned. + +======================================================================= + +std_memset() + +Description: + The std_memset() sets each byte in a block of memory to a value. + +Prototype: + + void *std_memset(void *p, int c, int nLen); + +Parameters: + p: memory block to set + c: value to set each byte to + nLen: size of p in bytes + +Return Value: + p + +======================================================================= + +std_memmove() + +Description: + The std_memmove() copies a block of memory from one buffer to another. + +Prototype: + + void *std_memmove(void *pTo, const void *cpFrom, int nLen); + +Parameters: + pTo: destination buffer + cpFrom: source buffer + nLen: number of bytes to copy + +Return Value: + pTo + +======================================================================= + +std_memsmove() + +Description: + + Size bounded memory move. + + Moves bytes from the source buffer to the destination buffer. + + This function ensures that there will not be a copy beyond + the size of the destination buffer. + + This function should be used in preference to memscpy() if there + is the possiblity of source and destination buffers overlapping. + The result of the operation is defined to be as if the copy were from + the source to a temporary buffer that overlaps neither source nor + destination, followed by a copy from that temporary buffer to the + destination. + +Prototype: + + int std_memsmove(void *dst, int dst_size, const void *src, int src_size); + +Parameters: + @param[out] dst Destination buffer. + @param[in] dst_size Size of the destination buffer in bytes. + @param[in] src Source buffer. + @param[in] src_size Number of bytes to copy from source buffer. + +Return value: + The number of bytes copied to the destination buffer. It is the + caller's responsibility to check for trunction if it cares about it - + truncation has occurred if the return value is less than src_size. + A negative return value indicates an error + +======================================================================= + +std_memcmp() + +Description: + The std_memcmp() compares two memory buffers, byte-wise. + +Prototype: + + int std_memcmp(const void *a, const void *b, int length); + +Parameters: + a, b: buffers to compare + length: number of bytes to compare + +Return Value: + 0 if buffers are the same for nLength ~ + < 0 if a is less than b ~ + > 0 if a is greater than b + +======================================================================= + +std_memscpy - Size bounded memory copy. + +Description: + + Copies bytes from the source buffer to the destination buffer. + + This function ensures that there will not be a copy beyond + the size of the destination buffer. + + The result of calling this on overlapping source and destination + buffers is undefined. + +Prototype: + + int std_memscpy(void *dst, int dst_size, const void *src, int src_size); + +Parameters: + + @param[out] dst Destination buffer. + @param[in] dst_size Size of the destination buffer in bytes. + @param[in] src Source buffer. + @param[in] src_size Number of bytes to copy from source buffer. + +Return value: + + The number of bytes copied to the destination buffer. It is the + caller's responsibility to check for trunction if it cares about it - + truncation has occurred if the return value is less than src_size. + Returs a negative value on error. + +======================================================================= + +std_memchr() + +Description: + The std_memchr() finds the first occurrence of a character in a memory + buffer. + +Prototype: + + void *std_memchr(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + A pointer to the occurrence of c. NULL if not found. + +======================================================================= + +std_memstr() + +Description: + The std_memstr() finds the first occurrence of a substring in a memory + buffer. + +Prototype: + + void *std_memstr(const char* cpHaystack, const char* cpszNeedle, + int nHaystackLen); + +Parameters: + cpHaystack: buffer to search + cpszNeedle: NUL-terminated string to search for + nHaystackLen: size of cpHaystack in bytes + +Return Value: + a pointer to the first occurrence of cpszNeedle if found, + NULL otherwise + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +std_memrchr() + +Description: + + The std_memrchr() finds the last occurrence of a character in a memory + buffer. + +Prototype: + + void *std_memrchr(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + a pointer to the last occurrence of c, NULL if not found + +======================================================================= + +std_memrchrbegin() + +Description: + The std_memrchrbegin() finds the last occurrence of a character in a + memory buffer. + +Prototype: + + void *std_memrchrbegin(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + a pointer to the last occurrence of c, or s if not found + +======================================================================= + +std_memchrend() + +Description: + The std_memchrend() finds the first occurrence of a character in a + memory buffer. + +Prototype: + + void *std_memchrend(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + a pointer to the occurrence of c, s + n if not found + +======================================================================= +std_memchrsend() + +Description: + The std_memchrsend() finds the first occurrence of any character in a + NUL-terminated list of characters in a memory buffer. + +Prototype: + + void *std_memchrend(const void* s, const char* cpszChars, int n); + +Parameters: + s: buffer to search + cpszChars: characters to look for + n: size of s in bytes + +Return Value: + a pointer to the first occurrence of one of cpszChars, s + n if not found + +======================================================================= + +std_strchr() + +Description: + The std_strchr() finds the first occurrence of a character in a + NUL-terminated string. + +Prototype: + + char *std_strchr(const char* s, int c); + +Parameters: + s: string to search + c: char to search for + +Return Value: + pointer to first occurrence, NULL if not found + +See Also: + std_wstrchr + +======================================================================= + +std_strchrs() + +Description: + The std_strchrs() searches s, a NUL-terminated string, for the first + occurrence of any characters in cpszSrch, a NUL-terminated list of + characters. + +Prototype: + + char *std_strchrs(const char* s, const char *cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + first occurrence of any of cpszSrch, NULL if not found + +======================================================================= + +std_strrchr() + +Description: + The std_strrchr() finds the last occurrence of a character in a + NUL-terminated string. + +Prototype: + + char *std_strrchr(const char* s, int c); + +Parameters: + s: string to search + c: char to search for + +Return Value: + pointer to last occurrence, NULL if not found + +See Also: + std_wstrrchr + +======================================================================= + +std_strchrend() + +Description: + The std_strchrend() finds the first occurrence of a character in a + NUL-terminated string. + +Prototype: + + char *std_strchrend(const char* s, int c); + +Parameters: + s: string to search + c: char to search for + +Return Value: + pointer to first occurrence, s + std_strlen(s) if not found + +======================================================================= + +std_strchrsend() + +Description: + The std_strchrsend() searches s, a NUL-terminated string, for the first + occurrence of any characters in cpszSrch, a NUL-terminated list of + characters. + +Prototype: + + char *std_strchrsend(const char* s, const char* cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + first occurrence of any of cpszSrch or s+strlen(s) if not found + +======================================================================= + +std_strends() + +Description: + The std_strends() tests whether a string ends in a particular suffix. + +Prototype: + + char *std_strends(const char* cpsz, const char* cpszSuffix); + +Parameters: + cpsz: string to test + cpszSuffix: suffix to test for + +Return Value: + the first character of cpsz+std_strlen(cpsz)-std_strlen(cpszSuffix) + if cpsz ends with cpszSuffix. NULL otherwise. + +======================================================================= + +std_striends() + +Description: + The std_striends() tests whether a string ends in a particular suffix, + case-folding ASCII characters. + +Prototype: + + char *std_striends(const char* cpsz, const char* cpszSuffix); + +Parameters: + cpsz: string to test + cpszSuffix: suffix to test for + +Return Value: + the first character of cpsz+std_strlen(cpsz)-std_strlen(cpszSuffix) + if cpsz ends with cpszSuffix. NULL otherwise. + +======================================================================= + +std_strbegins() + +Description: + The std_strbegins() tests whether a string begins with a particular + prefix string. + +Prototype: + + char *std_strbegins(const char* cpsz, const char* cpszPrefix); + +Parameters: + cpsz: string to test + cpszPrefix: prefix to test for + +Return Value: + cpsz + std_strlen(cpszPrefix) if cpsz does begin with cpszPrefix, + NULL otherwise + +======================================================================= + +std_stribegins() + +Description: + The std_stribegins() tests whether a string begins with a particular + prefix string, case-folding ASCII characters. + +Prototype: + + char *std_stribegins(const char* cpsz, const char* cpszPrefix); + +Parameters: + cpsz: string to test + cpszPrefix: prefix to test for + +Return Value: + cpsz + std_strlen(cpszPrefix) if cpsz does begin with cpszPrefix, + NULL otherwise + + +======================================================================= + +std_strcspn() + +Description: + The std_strcspn() function searches s, a NUL-terminated string, for + the first occurrence of any characters in cpszSrch, a NUL-terminated + list of characters. This function returns the length of the longest + initial substring of s which consists of characters not present in + cpszSrch. + +Prototype: + + int std_strcspn(const char* s, const char* cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + The index into the string s of the first occurrence of any of the + characters in cpszSrch. If no match is found, then index of the + terminating NUL character is returned. + +See Also: + std_strspn, std_strchr, std_strchrs + +======================================================================= + +std_strspn() + +Description: + The std_strspn() functions searches s, a NUL-terminated string, for + the first occurrence of a character that matches none of the + characters in cpszSrch, a NUL-terminated list of characters. This + function returns the length of the longest initial substring of s + which consists of characters present in cpszSrch. + +Prototype: + + int std_strspn(const char* s, const char* cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + The index into the string s of the first occurrence of any character + that matches none of the characters in cpszSrch. If all characters + in s are present in cpszSrch, the index of the terminating NUL + character is returned. + +See Also: + std_strcspn, std_strchr, std_strchrs + +======================================================================= + +std_wstrlcpy() + +Description: + + The std_wstrlcpy() function copies a string. It is equivalent to + str_strlcpy() except that it operates on wide (16-bit) character strings. + See std_strlcpy() for details. + + +Prototype: + + int std_wstrlcpy(AECHAR *pcDest, const AECHAR *pszSrc, int nDestSize); + +Parameters: + pcDst: destination string + pszSrc: source string + int nDestSize: size of pcDest __in AECHARs__ + +Return Value: + Returns the length of the string (in AECHARs) it tried to create, + which is same as length of pszSrc. + + Example: + + { + AECHAR buf[64]; + if (std_wstrlcpy(buf, file_name, STD_ARRAY_SIZE(buf)) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + +See Also: + std_wstrlcat + +======================================================================= + +std_wstrlcat() + +Description: + + The std_wstrlcat() function concatenates two strings. It is equivalent to + std_strlcat() except that it operates on wide (16-bit) character strings. + See std_strlcat() for more information. + +Prototype: + int std_wstrlcat(AECHAR *pcDst, const AECHAR *pszSrc, int nDestSize) + +Parameters: + pcDst[out]: Destination string + pcSrc : Source string + nDestSize: Size of the destination buffer in AECHARs + +Return Value: + Returns the length of the string (in AECHARs) it tried to create, + which is same as length of pszSrc + the length of pszDest. + + Example: + + { + char buf[64]; + if (std_wstrlcat(buf, file_name, STD_ARRAY_SIZE(buf)) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + +See Also: + std_wstrlcpy + +======================================================================= + +std_wstrncmp() + +Description: + + The std_wstrncmp() function compares up to a specified number of bytes + in two NUL-terminated strings. It is equivalent to std_strncmp() except + that it operates on wide (16-bit) character strings. + +Prototype: + int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen); + +Parameters: + s1, s2: strings to compare + n: maximum number of AECHARs to compare. if either s1 or s2 is + shorter than n, the function terminates there. + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_strncmp + +======================================================================= + +std_wstrcmp() + +Description: + The std_wstrcmp() compares two NUL-terminated strings. It is equivalent + to std_strncmp() except that it operates on wide (16-bit) character + strings. Comparison is strictly by byte values with no character set + interpretation. + +Prototype: + + int std_wstrcmp(const AECHAR* s1, const AECHAR* s2); + +Parameters: + s1, s2: strings to compare + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_strcmp + +======================================================================= + +std_wstrchr() + +Description: + This function is the wide string counterpart of std_strchr(). + The std_wstrchr() finds the first occurrence of a character in a + NUL-terminated wide (16-bit) character string. + +Prototype: + + AECHAR* std_wstrchr(const AECHAR* s, AECHAR ch); + +Parameters: + s: string to search + ch: char to search for + +Return Value: + pointer to first occurrence, NULL if not found + +See Also: + std_strchr + +======================================================================= + +std_wstrrchr() + +Description: + This function is the wide string counterpart of std_strrchr(). + The std_wstrrchr() finds the last occurrence of a character in a + NUL-terminated wide (16-bit) character string. + +Prototype: + + AECHAR* std_wstrrchr(const AECHAR* s, AECHAR ch); + +Parameters: + s: string to search + ch: char to search for + +Return Value: + pointer to last occurrence, NULL if not found + +See Also: + std_strrchr + +======================================================================= + +std_makepath() + +Description: + The std_makepath() constructs a path from a directory portion and a file + portion, using forward slashes, adding necessary slashes and deleting extra + slashes. This function guarantees NUL-termination of pszDest + +Prototype: + + int std_makepath(const char *cpszDir, const char *cpszFile, + char *pszDest, int nDestSize) + +Parameters: + cpszDir: directory part + cpszFile: file part + pszDest: output buffer + nDestSize: size of output buffer in bytes + +Return Value: + the required length to construct the path, not including + NUL-termination + +Comments: + The following list of examples shows the strings returned by + std_makepath() for different paths. + +Example: + + cpszDir cpszFile std_makepath() + "" "" "" + "" "/" "" + "/" "" "/" + "/" "/" "/" + "/" "f" "/f" + "/" "/f" "/f" + "d" "f" "d/f" + "d/" "f" "d/f" + "d" "/f" "d/f" + "d/" "/f" "d/f" + +See Also: + std_splitpath + +======================================================================= + +std_splitpath() + +Description: + The std_splitpath() finds the filename part of a path given an inclusive + directory, tests for cpszPath being in cpszDir. The forward slashes are + used as directory delimiters. + +Prototype: + + char *std_splitpath(const char *cpszPath, const char *cpszDir); + +Parameters: + cpszPath: path to test for inclusion + cpszDir: directory that cpszPath might be in + +Return Value: + the part of cpszPath that actually falls beneath cpszDir, NULL if + cpszPath is not under cpszDir + +Comments: + The std_splitpath() is similar to std_strbegins(), but it ignores trailing + slashes on cpszDir, and it returns a pointer to the first character of + the subpath. + + The return value of std_splitpath() will never begin with a '/'. + + The following list of examples shows the strings returned by + std_splitpath() for different paths. + +Example: + cpszPath cpszDir std_splitpath() + "" "" "" + "" "/" "" + "/" "" "" + "/" "/" "" + "/d" "d" null + "/d" "/" "d" + "/d/" "/d" "" + "/d/f" "/" "d/f" + "/d/f" "/d" "f" + "/d/f" "/d/" "f" + +See Also: + std_makepath + +======================================================================= + +std_cleanpath() + +Description: + The std_cleanpath() removes double slashes, ".", and ".." from + slash-delimited paths,. It operates in-place. + +Prototype: + + char *std_cleanpath(char *pszPath); + +Parameters: + pszPath[in/out]: path to "clean" + +Return Value: + pszPath + +Comments: + Passing an "fs:/" path to this function may produce undesirable + results. This function assumes '/' is the root. + +Examples: + pszPath std_cleanpath() + "", "", + "/", "/", + + // here"s, mostly alone + "./", "/", + "/.", "/", + "/./", "/", + + // "up"s, mostly alone + "..", "", + "/..", "/", + "../", "/", + "/../", "/", + + // fun with x + "x/.", "x", + "x/./", "x/", + "x/..", "", + "/x/..", "/", + "x/../", "/", + "/x/../", "/", + "/x/../..", "/", + "x/../..", "", + "x/../../", "/", + "x/./../", "/", + "x/././", "x/", + "x/.././", "/", + "x/../.", "", + "x/./..", "", + "../x", "/x", + "../../x", "/x", + "/../x", "/x", + "./../x", "/x", + + // double slashes + "//", "/", + "///", "/", + "////", "/", + "x//x", "x/x", + + +Side Effects: + None + +See Also: + None + + +======================================================================= + +std_basename() + +Description: + The std_basename() returns the filename part of a string, + assuming '/' delimited filenames. + +Prototype: + + char *std_basename(const char *cpszPath); + +Parameters: + cpszPath: path of interest + +Return Value: + pointer into cpszPath that denotes part of the string immediately + following the last '/' + +Examples: + cpszPath std_basename() + "" "" + "/" "" + "x" "x" + "/x" "x" + "y/x" "x" + "/y/x" "x" + + See Also: + None + +======================================================================= + +std_rand_next() + +Description: + The std_rand_next() generates pseudo-random bytes. + +Prototype: + + unsigned std_rand_next(unsigned uRand); + +Parameters: + uRand: a seed for the pseudo-random generator + +Return Value: + the next value in the generator from uRand + +Comments: + for best results, this function should be called with its last + generated output. + + This is an example of code to generate 256 bytes of pseudo-random data. + + This is not crypto quality and should not be used for key generation + and the like. + +Example: + { + unsigned rand_buf[256/sizeof(unsigned)]; + int i; + unsigned uLast = std_rand_next(uCurrentTime); + for (i = 0; i < STD_ARRAY_SIZE(rand_buf); i++) { + rand_buf[i] = (uLast = std_rand_next(uLast)); + } + } + +See Also: + std_rand() + +======================================================================= + +std_rand() + +Description: + The std_rand() functions generates pseudo-random bytes and places it + in an output buffer of specified size. + +Prototype: + + uint32 std_rand(uint32 uSeed, byte* pDest, int nSize); + +Parameters: + uSeed: A seed for the pseudo-random generator + pDest: The output buffer where the random bytes are placed. + nSize: The size in bytes of pDest. + +Return Value: + The new seed value that can be used in a subsequent call to + std_rand(). + +Comments: + + std_rand() is a linear congruent psuedo-random number generator that + is seeded using the input seed. This makes the ouput predictable if + you can determine (or influence) the seed value used. Furthermore, + the random sequence of bytes generated by two different calls to this + function will be identical if both the calls use the same seed value. + + This is not crypto quality and should not be used for key generation + and other cryptographic uses. + +See Also: + std_rand_next() + +======================================================================= + +std_CopyLE() + +Description: + + The std_CopyLE() function copies data while translating numeric values + between host byte ordering and "little endian" byte ordering. + + pvDest and pvSrc are NOT required to be 16 or 32-bit word aligned. + + Behavior is undefined when the destination and source arrays overlap, + except in the special case where pvDest and pvSrc are equal. In that case, + std_CopyLE() modifies the buffer in-place. + + When the target byte ordering (little endian) matches the host byte + ordering, in-place translations reduce to a no-op, and copies are + delegated directly to std_memmove(). + + +Prototype: + int std_CopyLE(void *pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields); + +Parameters: + pvDest: Pointer to destination buffer. + nDestSize: Size of the destination buffer. + pvSrc: Pointer to buffer containing source data. + nSrcSize: Size of source data. + pszFields: Description of the fields that comprise the source data. + + Each field size is given by a positive decimal integer or one of + the following characters: "S", "L", "Q", or "*". The letters + denote fields that should be converted to the desired byte + ordering: + +===pre> + S : a 2 byte (16 bit) value. + L : a 4 byte (32 bit) value. + Q : a 8 byte (64 bit) value. +===/pre> + + An integer gives a number of bytes and "*" represents the + remainder of the pvSrc[] buffer. No reordering is performed on + data in these fields. + + Comparisons are case-sensitive. Behavior is undefined when + other characters are supplied in pszFields. + + For example: "L12S*" would be appropriate to copy a structure + containing a uint32 followed by a 12 byte character array, + followed by a uint16, followed by an arbitrary amount of + character data. + + If nSrcSize is greater than the structure size (total of all the + sizes in pszFields[]) then pvSrc[] is treated as an array of + structures, each of which is described by pszFields. + +Return Value: + + The number of bytes actually copied or translated in-place. This will be + the smaller of nDestSize and nSrcSize, or zero if one of them are negative. + + +======================================================================= + +std_CopyBE() + +Description: + + The std_CopyBE() function has the same semantics as std_CopyLE() except it + copies between host byte ordering and big-endian ("network") byte order. + + See std_CopyLE() for more details. + + +Prototype: + void *std_CopyBE(void *pvDest, const void *pvSrc, + int cbDest, int nItems, const char *pszFields); + +Parameters: + pvDest: Pointer to destination buffer. + nDestSize: Size of the destination buffer. + pvSrc: Pointer to buffer containing source data. + nSrcSize: Size of source data. + pszFields: Description of the fields that comprise the source data, + as defined in std_CopyLE. + +Return Value: + + The number of bytes actually copied or translated in-place. This will be + the smaller of nDestSize and nSrcSize, or zero if one of them are negative. + +======================================================================= + +std_swapl() + +Description: + The std_swapl() changes endianness of an unsigned long. + +Prototype: + + unsigned long std_swapl(unsigned long ul) + +Parameters: + ul: input unsigned long + +Return Value: + ul, reversed in byte-ordering + +======================================================================= + +std_swaps() + +Description: + The std_swaps() changes endianness of an unsigned short. + +Prototype: + + unsigned short std_swaps(unsigned short us) + +Parameters: + us: input unsigned short + +Return Value: + us, reversed in byte-ordering + +======================================================================= + +std_letohs() + +Description: + The std_letohs() changes a short from little-endian to host byte order. + +Prototype: + + unsigned short std_letohs(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from little-endian to host byte order. If the + host is little endian, just returns us + +======================================================================= + +std_htoles() + +Description: + The std_htoles() converts a short from host byte-order to little-endian. + +Prototype: + + unsigned short std_htoles(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from host byte order to little-endian. If the + host is little endian, just returns us + +======================================================================= + +std_letohl() + +Description: + The std_letohl() changes a long from little-endian to host byte order. + +Prototype: + + unsigned long std_letohl(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from little-endian to host byte order. If the + host is little endian, just returns ul + +======================================================================= + +std_htolel() + +Description: + The std_htolel() converts a long from host byte-order to little-endian. + +Prototype: + + unsigned long std_htolel(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from host byte order to little-endian. If the + host is little endian, just returns ul. + + +======================================================================= + +std_ntohs() + +Description: + The std_ntohs() changes a short from big-endian to host byte order. + +Prototype: + + unsigned short std_ntohs(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from big-endian to host byte order. If the + host is big endian, just returns us. + +======================================================================= + +std_htons() + +Description: + The std_htons() converts a short from host byte-order to big-endian. + +Prototype: + + unsigned short std_htons(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from host byte order to big-endian. If the + host is big endian, just returns us. + +======================================================================= + +std_ntohl() + +Description: + The std_ntohl() changes a long from big-endian to host byte order. + +Prototype: + + unsigned long std_ntohl(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from big-endian to host byte order. If the + host is big endian, just returns ul. + +======================================================================= + +std_htonl() + +Description: + The std_htonl() converts a long from host byte-order to big-endian. + +Prototype: + + unsigned long std_htonl(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from host byte order to big-endian. If the + host is big endian, just returns ul. + + +======================================================================= + +std_strlprintf() + +Description: + + The functions std_strlprintf() and std_vstrlprintf() write formatted + output to a string. These functions guarantee NUL-termination of + the output buffer when its size is greater than zero. + + A format string is copied to the output buffer, except for conversion + specifiers contained within the format string. Conversion specifiers + begin with a "%" and specify some action that consumes an argument from + the argument list. + + Conversion specifiers have the following form: +===pre> + %[FLAGS] [WIDTH] [.PRECISION] [TYPE] CONV +===/pre> + + CONV is the only required field. It is always a single character, + and determines the action to be taken. Supported values are: + +===pre> + CONV | Description + ======|======================================================= + c | Output a single character. + | + s | Output a NUL-terminated single-byte character string. + | + d, i | Ouptut a signed decimal integer. + | + u | Output an unsigned decimal integer. + | + o | Output an unsigned octal integer. + | + x | Output an unsigned hexadecimal integer, using + | lower case digits. + | + X | Output an unsigned hexadecimal integer, using + | upper case digits. + | + p | Output a pointer value as eight hexadecimal digits, + | using upper case digits. +===/pre> + + The next argument from the argument list supplies the value to be + formatted and output. + + FLAGS, WIDTH, and PRECISION can modify the formatting of the value. + + FLAGS consists of one or more of the following characters: + +===pre> + Flag | Meaning + =====|================================================================= + + | Prefix positive numbers with "+" (%d and %i only). + -----|----------------------------------------------------------------- + - | When padding to meet WIDTH, pad on the right. + -----|----------------------------------------------------------------- + 0 | Pad with '0' characters when padding on the left to meet WIDTH. + -----|----------------------------------------------------------------- + blank| Prefix positive numbers with " " (%d and %i only). + space| + -----|----------------------------------------------------------------- + # | With %x or %X: prefixes non-zero values with "0x"/"0X". + | With %o, ensure the value begins with "0" (increasing PRECISION + | if necessary). + | Ignored for all other CONV specifiers. + -----|----------------------------------------------------------------- +===/pre> + + WIDTH is an unsigned decimal integer or the character "*". + + WIDTH gives the minimum number of characters to be written. The + formatted value will be padded with spaces until the minimum size is + met; it never causes a value to be truncated The sign of the WIDTH + integer selects between left and right padding. Padding will be on + the left unless the "-" flag is specified. + + When "*" is used, an 'int' argument is consumed from the argument + list and used as the WIDTH. A negative argument specifies padding on + the right, and its absolute value gives the amount of padding. + + If the "0" flags is specified, any padding on the left will consist + of "0" characters. An exception to this rule is that the "0" flag is + ignored when precision is specified for a numeric value. + + PRECISION is a non-negative decimal integer or "*" preceded by ".". + + When PRECISION accompanies any of the numeric conversions, it + specifies the minimum number of digits to output. Values are padded + on the left with '0' to meet the specified size. PRECISION defaults + to 1 for numbers. + + When PRECISION accompanies other conversions, it specifies the + maximum number of characters from the value to output. The value + will be truncated to ensure that at most PRECISION characters are + output. + + TYPE provides information about the type of arguments. This is used + to determine the size of integer arguments. Values larger than 'int' + can be properly obtained from the argument list. Their behavior + should be considered undefined for CONV operations other than integer + formatting. + +===pre> + TYPE | Meaning + =======|===================== + hh | sizeof(char) + -------|--------------------- + h | sizeof(short) + -------|--------------------- + l | sizeof(long) + -------|--------------------- + L, ll | sizeof(long long) + -------|--------------------- + j | sizeof(int64) + -------|--------------------- + z | sizeof(size_t) + -------|--------------------- +===/pre> + + For 64-bit integers, "ll" may be the most widely-supported type + specifier in other printf implementation, but "j" has been introduced + in ISO C99. This implementation supports both. + + Note that arguments to variadic functions are promoted to 'int' when + smaller than 'int', so 'h' and 'hh' have no observable effect. + Static analysis tools that understand standard format string syntax + may use this information for other purposes. + +Prototype: + + int std_strlprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + +Return Value: + + The size required to hold the entire untruncated output, NOT + including NUL-termination. + +Comments: + + Notable omissions from std_strlprintf() are lack of support for + floating point and lack of support for "%n". + +Side Effects: + None + +See Also: + None + +======================================================================= + +std_vstrlprintf() + +Description: + + The std_vstrlprintf() is documented with std_strlprintf(), it's the + vector form of std_strlprintf(). See std_strlprintf() for a + more complete description. + +Prototype: + int std_vstrlprintf(char *pszDest, int nDestSize, + const char *pszFmt, AEEVaList args); + +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + args: arguments + + +======================================================================= + +std_snprintf() + +Description: + + The functions std_snprintf() and std_vsnprintf() are similar to + std_strlprintf and std_vstrlprintf that write formatted output to a + string. Unlike std_strlprintf, std_snprintf also support the floating + point conversion specifiers. These functions guarantee NUL-termination + of the output buffer when its size is greater than zero. + + A format string is copied to the output buffer, except for conversion + specifiers contained within the format string. Conversion specifiers + begin with a "%" and specify some action that consumes an argument from + the argument list. + + Conversion specifiers have the following form: +===pre> + %[FLAGS] [WIDTH] [.PRECISION] [TYPE] CONV +===/pre> + + CONV is the only required field. It is always a single character, + and determines the action to be taken. For a detailed description of + conversion sepcifiers, please refer to the documentation of + std_strlprintf(). Here. we only provide description of these fields + as it applies to the additional CONV values supported by + std_snprintf(). + + In addition to the values for CONV supported by std_strlprintf, this + function supports the following values: + +===pre> + CONV | Description + ======|======================================================= + e, E | Outputs a double value representing a floating point + | number in the style [-]d.ddd e±dd, where there is one + | digit (which is nonzero if the argument is nonzero) + | before the decimal-point character and the number of + | digits after it is equal to the precision. If the + | precision is missing, it is taken as 6. If the precision + | is zero and the # flag is not specified, no decimal-point + | character appears. The value is rounded to the appropriate + | number of digits. The E conversion specifier produces a + | number with E instead of e introducing the exponent. The + | exponent always contains at least two digits, and only as + | many more digits as necessary to represent the exponent. + | If the value is zero, the exponent is zero. + | + f, F | Outputs a double value representing a floating point + | number in the style [-]ddd.ddd, where the number of + | digits after the decimal-point character is equal to the + | precision specification. If the precision is missing, it + | is taken as 6. If the precision is zero and the # flag is + | not specified, no decimal-point character appears. If a + | decimal-point character appears, at least one digit + | appears before it. The value is rounded to the appropriate + | number of digits. + | + g, G | Outputs a double value representing a floating point + | number in the style f or e (or in style F or E in the case + | of a G conversion specifier), with the precision specifying + | the number of significant digits. If the precision is zero, + | it is taken as 1. The style used depends on the value + | converted. Style e (or E) is used only if the exponent + | resulting from such a conversion is less than -4 or greater + | than or equal to the precision. Trailing zeros are removed + | from the fractional portion of the result unless the # flag + | is specified; a decimal-point character appears only if it + | is followed by a digit. + | + a, A | Outputs a double value representing a floating point + | number in the style [-]0xh.hhhh p±d, where there is one + | non-zero hexadecimal digit before the decimal-point + | character and the number of hexadecimal digits after it is + | equal to the precision. If the precision is missing then + | the precision is assumed to be sufficient for an exact + | representation of the value, except that trailing zeros + | may be omitted. If the precision is zero and the # flag is + | not specified, no decimal point character appears. The + | letters 'abcdef' are used for '%a' conversion and the + | letters ABCDEF for '%A' conversion. The '%A' conversion + | specifier produces a number with 'X' and 'P' instead of 'x' + | and 'p'. The exponent always contains at least one digit, + | and only as many more digits as necessary to represent the + | decimal exponent of 2. If the value is zero, the exponent + | is zero. + | +===/pre> + + For 'e', 'f', 'g' and 'a' convervsion specifiers, a double argument + representing an infinity is converted in to the style '[-]inf' and + a double argument representing a NaN is converted in to the stlye + 'nan'. The 'E', 'F', 'G' and 'A' conversion specifiers result in + 'INF' or 'NAN' instead of 'inf' or 'nan', respectively. + +Prototype: + + int std_snprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + +Return Value: + + The size required to hold the entire untruncated output, NOT + including NUL-termination. + +Comments: + + Notable omissions from std_strlprintf() lack of support for "%n". + +Side Effects: + None + +See Also: + std_strlprintf() + +======================================================================= + +std_vsnprintf() + +Description: + + The std_vsnprintf() is documented with std_snprintf(), it's the + vector form of std_snprintf(). See std_snprintf() for a more complete + description. + +Prototype: + int std_vsnprintf(char *pszDest, int nDestSize, + const char *pszFmt, AEEVaList args); + +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + args: arguments + + +======================================================================= + +std_scanul() + +Description: + + The std_scanul() converts an ASCII representation of a number to an unsigned + long. It expects strings that match the following pattern: +===pre> + spaces [+|-] digits +===/pre> + + 'Spaces' is zero or more ASCII space or tab characters. + + 'Digits' is any number of digits valid in the radix. Letters 'A' through + 'Z' are treated as digits with values 10 through 35. 'Digits' may begin + with "0x" when a radix of 0 or 16 is specified. + + Upper and lower case letters can be used interchangeably. + + +Prototype: + + uint32 std_scanul( const char *pchBuf, int nRadix, const char **ppchEnd, + int *pnError) + +Parameters: + + pchBuf [in] : the start of the string to scan. + + nRadix [in] : the numeric radix (or base) of the number. Valid values are + 2 through 36 or zero, which implies auto-detection. + Auto-detection examines the digits field. If it begins with + "0x", radix 16 is selected. Otherwise, if it begins with + "0" radix 8 is selected. Otherwise, radix 10 is selected. + + ppchEnd [out] : if ppchEnd is not NULL, *ppchEnd points to the first + character that did not match the expected pattern shown + above, except on STD_BADPARAM and STD_OVERFLOW when it is + set to the start of the string. + + pnError [out] : If pnError is not NULL, *pnError holds the error code, + which is one of the following: +~ + 0 : Numeric value is from 0 to MAX_UINT32. + + STD_NEGATIVE : The scanned value was negative and its absolute value was + from 1 to MAX_UINT32. The result is the negated value + (cast to a uint32). + + STD_NODIGITS : No digits were found. The result is zero. + + STD_OVERFLOW : The absolute value exceeded MAX_UINT32. The result + is set to MAX_UINT32 and *ppchEnd is set to pchBuf. + + STD_BADPARAM : An improper value for nRadix was received. The result + is set to zero, and *ppchEnd is set to pchBuf. +* + +Return Value: + + The converted numeric result. + +Comments: + + The std_scanul() is similar to ANSI C's strtoul() but differs in the following + respects: + + 1. It returns an error/success code. strtoul() results are ambiguous + unless the caller sets errno to zero before calling it. + + 2. std_scanul() is free of references to current locale and errno. Some + strtoul() implementations use locale; some don't. + + 3. It provides more complete reporting of range underflow. strtoul() + does not distinguish between "-1" and "0xFFFFFFFF", and underflow is + poorly defined. + + 4. std_scanul() reports a "no digits" error code to distinguish "0" from + whitespace, "+", etc.. + +See Also: + + std_scanull() + +======================================================================= + +std_scanull() + +Description: + + The std_scanull() converts an ASCII representation of a number to an + unsigned long long. It expects strings that match the following pattern: +===pre> + spaces [+|-] digits +===/pre> + + 'Spaces' is zero or more ASCII space or tab characters. + + 'Digits' is any number of digits valid in the radix. Letters 'A' through + 'Z' are treated as digits with values 10 through 35. 'Digits' may begin + with "0x" when a radix of 0 or 16 is specified. + + Upper and lower case letters can be used interchangeably. + + +Prototype: + + uint64 std_scanull(const char *pchBuf, int nRadix, const char **ppchEnd, + int *pnError) + +Parameters: + + pchBuf [in] : the start of the string to scan. + + nRadix [in] : the numeric radix (or base) of the number. Valid values are + 2 through 36 or zero, which implies auto-detection. + Auto-detection examines the digits field. If it begins with + "0x", radix 16 is selected. Otherwise, if it begins with + "0" radix 8 is selected. Otherwise, radix 10 is selected. + + ppchEnd [out] : if ppchEnd is not NULL, *ppchEnd points to the first + character that did not match the expected pattern shown + above, except on STD_BADPARAM and STD_OVERFLOW when it is + set to the start of the string. + + pnError [out] : If pnError is not NULL, *pnError holds the error code, + which is one of the following: +~ + 0 : Numeric value is from 0 to MAX_UINT64. + + STD_NEGATIVE : The scanned value was negative and its absolute value was + from 1 to MAX_UINT64. The result is the negated value + (cast to a uint64). + + STD_NODIGITS : No digits were found. The result is zero. + + STD_OVERFLOW : The absolute value exceeded MAX_UINT64. The result + is set to MAX_UINT64 and *ppchEnd is set to pchBuf. + + STD_BADPARAM : An improper value for nRadix was received. The result + is set to zero, and *ppchEnd is set to pchBuf. +* + +Return Value: + + The converted numeric result. + +Comments: + + The std_scanull() is similar to ANSI C's strtoull() but differs in the following + respects: + + 1. It returns an error/success code. strtoull() results are ambiguous + unless the caller sets errno to zero before calling it. + + 2. std_scanull() is free of references to current locale and errno. Some + strtoull() implementations use locale; some don't. + + 3. It provides more complete reporting of range underflow. strtoul() + does not distinguish between "-1" and "0xFFFFFFFFFFFFFFFF", and underflow + is poorly defined. + + 4. std_scanull() reports a "no digits" error code to distinguish "0" from + whitespace, "+", etc.. + +See Also: + + std_scanul() + +======================================================================= + +std_qsort() + +Description: + + An implementation of the quicksort algorithm, a massively recursive, + in-place sorting algorithm for an array. + + The contents of the array are sorted in ascending order according to + the comparison function pointed to by pfnCompare. + + pfnCompare must return a value less than, equal to, or + greater than zero if the first argument is considered to be + less than, equal to, or greater than the second, respectively. + + std_qsort() is not a stable sort. + +Prototype: + void std_qsort(void* pElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + + +Parameters: + pElems: array of elements to be sorted in place. It's size + must be nNumElems * nElemWidth in bytes. + nNumElems: number of elements in pElems + nElemWidth: the width, in bytes of each element of pElems + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + None + +Comments: + If nElemWidth is 2, 4, or 8, pElems is accessed internally as + integer values for the purposes of reading and writing elements. + Therefore, pElems must be aligned on a memory boundary compatible + with integer access of the array elements. I.e. if you pass 4 as + nElemWidth, *(int*)pElems must succeed. + +======================================================================= + +std_bisect() + +Description: + + Find an element in a sorted array of elements. Uses a binary + search. + +Prototype: + int std_bisect(const void* pElems, int nNumElems, int nElemWidth, + const void* pElemFind, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +Parameters: + pElems: array of elements to be searched. It's size + must be nNumElems * nElemWidth in bytes. + nNumElems: number of elements in pElems + nElemWidth: the width, in bytes of each element of pElems + pElemFind: the element value to find in the array + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + index of the element such that pElems[index] <= elem < pElems[index + 1] + nNumElems if elem is greater than all the elements in the list + 0 if the elem is less than or equal to the all the elements in the list + +======================================================================= + +std_merge() + +Description: + + Merge two sorted arrays into another array. + +Prototype: + void std_merge(void* vpDst, int nDst, + const void* vpA, int nA, + const void* vpB, int nB, + int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +Parameters: + vpDst: destination array. It's size must be nDst * nElemWidth in bytes. + nDst: number of elements that vpDst can accomodate + vpA: array of elements to be merged, it's size must be nA * nElemWidth + in bytes. + nA: number of elements in vpA + vpB: array of elements to be merged, it's size must be nB * nElemWidth + in bytes. + nB: number of elements in vpB + nElemWidth: the width, in bytes of each element of pElems + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + none + +======================================================================= + +std_uniq() + +Description: + Removes duplicate entries from a sorted array. + +Prototype: + int std_uniq(void* vpElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +Parameters: + pElems: array of elements to be searched. It's size + must be nNumElems * nElemWidth in bytes. + nNumElems: number of elements in pElems + nElemWidth: the width, in bytes of each element of pElems + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + the number of uniq elements left in vpElems + +======================================================================= + +std_scand() + +Description: + + The std_scand() converts the initial portion of an input ASCII string + to it's corresponding floating point value. It expects the input + string to match the following pattern: +===pre> + <Spaces><Subject String><Rest Of The String> +===/pre> + + 'Spaces' - is zero or more ASCII space or tab characters. + 'Subject String' - is the part of the input string that represents a + valid floating point constant. + 'Rest Of The String' - is the remaining sequence of one or more + characters including the terminating null + character of the input string. + + A valid subject string can be one of the following: + -- <NAN>, ignoring case. This is interpreted as a quiet NAN. + -- [+|-]<INF|INFINITY>, ignoring case. This is interpreted as an + infinity. + -- [+|-]<Valid Floating Point Number> + + In general, a valid floating poing number can either be a decimal + number or an hexadecimal number, and has the following form: + <Integral Part>[.[<Fractional Part>]][<Exponent>] + where the intergral, fractional and the exponent part may consist of + sequence of valid decimal or hexadecimal digits. More specifically: + + For a decimal floating point number: + 'Integral Part' - <Decimal Digits> + 'Fractional Part' - <Decimal Digits> + 'Exponent' - <e|E><Decimal Digits> + For a hexadecimal floating point number: + 'Integral Part' - <Hexadecimal Digits> + 'Fractional Part' - <Hexadecimal Digits> + 'Exponent' - <p|P><Decimal Digits> + + where: + 'Decimal Digits' - is any number of digits in the range [0,10]. + 'Hexadecimal Digits' - is any number of digits in the range [0,10] + or the alphabets A through F. + 'e','E','p','P' - represent the exponent characters + +Prototype: + + double std_scand(const char *pchBuf, const char **ppchEnd); + +Parameters: + + pchBuf [in] : the start of the string to scan. + + ppchEnd [out] : if ppchEnd is not NULL, *ppchEnd points to the first + character after the parsed number. + +Return Value: + + This function returns the converted numeric result. If the string + does not contain a valid floating point number then the function + returns zero. If the converted value is outside the range of + representable values (overflow), [-]INFINITY is + returned. In case of an underflow, the function returns zero. + +=======================================================================*/ + +#endif // AEESTD_H + + diff --git a/inc/HAP_debug.h b/inc/HAP_debug.h new file mode 100644 index 0000000..c4c2b8c --- /dev/null +++ b/inc/HAP_debug.h @@ -0,0 +1,102 @@ +#ifndef HAP_DEBUG_H +#define HAP_DEBUG_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 "AEEStdDef.h" +#include <stdarg.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define HAP_LEVEL_LOW 0 +#define HAP_LEVEL_MEDIUM 1 +#define HAP_LEVEL_HIGH 2 +#define HAP_LEVEL_ERROR 3 +#define HAP_LEVEL_FATAL 4 + +#define HAP_LEVEL_RUNTIME (1 << 5) + +//Add a weak reference so shared objects work with older images +#pragma weak HAP_debug_v2 + +//Add a weak reference so runtime FARFs are ignored on older images +#pragma weak HAP_debug_runtime + +/************************************************************************** + These HAP_debug* functions are not meant to be called directly. + Please use the FARF() macros to call them instead +**************************************************************************/ +void HAP_debug_v2(int level, const char* file, int line, const char* format, ...); +void HAP_debug_runtime(int level, const char* file, int line, const char* format, ...); +int HAP_setFARFRuntimeLoggingParams(unsigned int mask, const char* files[], + unsigned short numberOfFiles); + +// Keep these around to support older shared objects and older images +void HAP_debug(const char *msg, int level, const char *filename, int line); + +static __inline void _HAP_debug_v2(int level, const char* file, int line, + const char* format, ...){ + char buf[256]; + va_list args; + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + HAP_debug(buf, level, file, line); +} + +/*! +This function is called to log an accumlated log entry. If logging is +enabled for the entry by the external device, then the entry is copied +into the diag allocation manager and commited. + + [in] log_code_type ID of the event to be reported + [in] *data data points to the log which is to be submitted + [in] dataLen The length of the data to be logged. + +Returns + TRUE if log is submitted successfully into diag buffers + FALSE if there is no space left in the buffers. + +*/ +boolean HAP_log_data_packet(unsigned short log_code_type, unsigned int dataLen, + byte* data); + +#define HAP_DEBUG_TRACEME 0 + +long HAP_debug_ptrace(int req, unsigned int pid, void* addr, void* data); + +#ifdef __cplusplus +} +#endif + +#endif // HAP_DEBUG_H + diff --git a/inc/HAP_farf.h b/inc/HAP_farf.h new file mode 100644 index 0000000..48e123a --- /dev/null +++ b/inc/HAP_farf.h @@ -0,0 +1,226 @@ +#ifndef HAP_FARF_H +#define HAP_FARF_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 "AEEStdDef.h" +#include "HAP_debug.h" + +/** + * FARF macro used for logging + * + * Compile time logging options + * ----------------------------- + * + * Logging is controlled via conditional compilation. A FARF + * level should be defined to 1 for FARF macros to be compiled + * in. For example: + * + * #define FARF_LOW 1 + * #include "HAP_farf.h" + * + * FARF(LOW, "something happened: %s", (const char*)string); + * + * If FARF_LOW is defined to 0, as it is by default, the above + * FARF string will not be compiled in, if it is defined to 1 it + * will be compiled in. Users can also define their own custom + * levels. For example: + * + * #include "HAP_farf.h" + * #define FARF_MYTRACE 1 + * #define FARF_MYTRACE_LEVEL HAP_LEVEL_LOW + * + * FARF(MYTRACE, "custom trace in file %s on line %d", __FILE__, __LINE__); + * + * The LEVEL define tells FARF what logging level to + * use. These are mapped to their diag level counterparts, in + * the above example the message will be logged to diag's LOW + * level. + * + * Messages logged with ALWAYS level are always compiled in and logged + * ------ + * + * When building the Debug variant or builds defining _DEBUG the + * following FARF levels will be enabled: + * + * HIGH + * ERROR + * FATAL + * + * + * + * Run time logging options + * -------------------------- + * + * In order to enable run-time logging (logging that can be enabled / disabled + * at run-time), the FARF_RUNTIME_* macros should be used. + * + * Log messages sent with these macros are compiled in by default. However by + * these messages WILL NOT be logged by default. In order to enable logging, + * the FASTRPC process will need to either call the + * HAP_SetFARFRuntimeLoggingParams() API, or by adding a <process_name>.farf + * file to the HLOS file system with the appropriate contents. + * + * #include "HAP_farf.h" + * FARF(RUNTIME_HIGH, "something happened: %s", (const char*)string); + * + */ + + + /* + * @param x, the FARF level defined to either 0 to disable compilation or 1 to enable. + * @param ..., format string and arguments. + */ +#define FARF(x, ...) _FARF_PASTE(_FARF_,_FARF_VAL(FARF_##x))(x, ##__VA_ARGS__) + +/* by default _DEBUG turns on ALWAYS, HIGH, ERROR, FATAL + * + */ +#ifdef _DEBUG +#ifndef FARF_HIGH +#define FARF_HIGH 1 +#endif +#ifndef FARF_ERROR +#define FARF_ERROR 1 +#endif +#ifndef FARF_FATAL +#define FARF_FATAL 1 +#endif +#endif + +/* Compile time macros. Set these to 1 to enable logging at that + level. Setting them to 0 will cause them to be COMPILED out . + + Example Usage: + #define FARF_HIGH 1 + FARF(HIGH,"Log message"); + + Defining _DEBUG will automatically enable compiled log messages with + priority higher than HIGH. + + The ALWAYS macro will cause log messages to be ALWAYS compiled in. + FARF(ALWAYS,"Log message") +*/ + +#ifndef FARF_ALWAYS +#define FARF_ALWAYS 1 /* 0 turns me off */ +#endif +#define FARF_ALWAYS_LEVEL HAP_LEVEL_HIGH + +#ifndef FARF_LOW +#define FARF_LOW 0 /* 0 turns me off */ +#endif +#define FARF_LOW_LEVEL HAP_LEVEL_LOW + +#ifndef FARF_MEDIUM +#define FARF_MEDIUM 0 /* 0 turns me off */ +#endif +#define FARF_MEDIUM_LEVEL HAP_LEVEL_MEDIUM + +#ifndef FARF_HIGH +#define FARF_HIGH 0 /* 0 turns me off */ +#endif +#define FARF_HIGH_LEVEL HAP_LEVEL_HIGH + +#ifndef FARF_ERROR +#define FARF_ERROR 0 /* 0 turns me off */ +#endif +#define FARF_ERROR_LEVEL HAP_LEVEL_ERROR + +#ifndef FARF_FATAL +#define FARF_FATAL 0 /* 0 turns me off */ +#endif +#define FARF_FATAL_LEVEL HAP_LEVEL_FATAL + +/* Runtime FARF macros. FARFs with these levels can be enabled at runtime. + They are turned OFF by default. + + Example Usage: + + FARF(RUNTIME_HIGH,"Log message"); +*/ +#ifndef FARF_RUNTIME_LOW +#define FARF_RUNTIME_LOW 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_LOW_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_LOW) + +#ifndef FARF_RUNTIME_MEDIUM +#define FARF_RUNTIME_MEDIUM 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_MEDIUM_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_MEDIUM) + +#ifndef FARF_RUNTIME_HIGH +#define FARF_RUNTIME_HIGH 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_HIGH_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_HIGH) + +#ifndef FARF_RUNTIME_ERROR +#define FARF_RUNTIME_ERROR 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_ERROR_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_ERROR) + +#ifndef FARF_RUNTIME_FATAL +#define FARF_RUNTIME_FATAL 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_FATAL_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_FATAL) + +//internal macros +#define _FARF_PASTE(a,b) _FARF_PASTE_(a,b) +#define _FARF_PASTE_(a,b) a##b +#define _FARF_VAL(a) a + +//internal macro +//this one is used when farfs are not compiled in +#define _FARF_0(x, ...) + +#ifndef __FILENAME__ +#define __FILENAME__ __FILE__ +#endif + +//lint -emacro(506,FARF) Constant Boolean Value +//lint -emacro(774,FARF) Boolean within always evaluates to True +//this one is used when farfs are compiled in +#define _FARF_1(x, ...) \ + do { \ + if(0 == (HAP_debug_v2)) { \ + _HAP_debug_v2(FARF_##x##_LEVEL, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + } else { \ + if (FARF_##x##_LEVEL & HAP_LEVEL_RUNTIME) { \ + if (0 != HAP_debug_runtime) { \ + HAP_debug_runtime(FARF_##x##_LEVEL ^ HAP_LEVEL_RUNTIME , __FILENAME__, __LINE__, ##__VA_ARGS__); \ + } else { \ + break; \ + } \ + } else { \ + HAP_debug_v2(FARF_##x##_LEVEL, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + } \ + } \ + } while (0) + +#endif /* #ifndef HAP_FARF_H */ diff --git a/inc/HAP_pls.h b/inc/HAP_pls.h new file mode 100644 index 0000000..23d7ddd --- /dev/null +++ b/inc/HAP_pls.h @@ -0,0 +1,129 @@ +#ifndef HAP_PLS_H +#define HAP_PLS_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 <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Process local storage is local storage for the hlos process context. + * + * Warning, this API should only be called from within a thread started by FastRPC, and not from + * any user created threads via the qurt apis. + * + * When used from within a FastRPC started thread this will attach + * desturctors to the lifetime of the HLOS process that is making the + * rpc calls. Users can use this to store context for the lifetime of + * the calling process on the hlos. + * + * Recovering instances + * -------------------- + * + * To maintain the same instance structure for a caller from the HLOS users + * can use the HAP_pls_add_lookup api, which will lookup the key, and add it + * if its not already present. + * For example: + * + * static int my_instance(struct my_struct* me) { + * return HAP_pls_add_lookup((uintptr_t)my_ctor, //type, some unique static address + * 0, //key, for different type instances + * sizeof(*me), //size of our struture + * my_ctor, //structure ctor + * 0, //aditional user context for ctor + * my_dtor, //desturctor + * &me); //result + * } + * + * First call to my_instance will initialize the structure by allocating it and calling my_ctor. + * Second call to my_instance will return the created instance. + * This API is thread safe, but when two threads try to intialize the structure the first + * time they may both create an instance, but only 1 will be returned. + * The destructor will be called when the HLOS process exits. + * + * See HAP_pls_add and HAP_pls_add_lookup. + * + * Exit Hooks + * ---------- + * + * Users can use either HAP_pls_add_lookup or HAP_pls_add to add a destructor that will be + * called when the HLOS process exits. The main difference between the two functions is that + * HAP_pls_add will always add, and the last instance added will be the one returned by + * HAP_pls_lookup. + * + * + */ + +/** + * adds a new type/key to the local storage, overriding + * any previous value at the key. Overriding the key + * does not cause the destructor to run. Destructors are + * run when the HLOS process exits. + * + * @param type, type part of the key to be used for lookup, + * these should be static addresses, like the address of a function. + * @param key, the key to be used for lookup + * @param size, the size of the data + * @param ctor, constructor that takes a context and memory of size + * @param ctx, constructor context passed as the first argument to ctor + * @param dtor, destructor to run at pls shutdown + * @param ppo, output data + * @retval, 0 for success + */ +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); + +/** + * Like add, but will only add 1 item, and return the same item on the + * next add. If two threads try to call this function at teh same time + * they will both receive the same value as a result, but the constructors + * may be called twice. + * item if its already there, otherwise tries to add. + * ctor may be called twice + * callers should avoid calling pls_add for the same type/key which will override the singleton + */ +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); + +/** + * finds the last data pointer added for key to the local storage + * + * @param key, the key to be used for lookup + * @param ppo, output data + * @retval, 0 for success + */ +int HAP_pls_lookup(uintptr_t type, uintptr_t key, void** ppo); + + +#ifdef __cplusplus +} +#endif +#endif //HAP_PLS_H diff --git a/inc/adsp_current_process.h b/inc/adsp_current_process.h new file mode 100644 index 0000000..a9bf630 --- /dev/null +++ b/inc/adsp_current_process.h @@ -0,0 +1,74 @@ +/** + * 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_CURRENT_PROCESS_H +#define _ADSP_CURRENT_PROCESS_H +#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 +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_exit)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_thread_exit)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_set_logging_params)(unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_getASID)(unsigned int* asid) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS_H diff --git a/inc/adsp_current_process1.h b/inc/adsp_current_process1.h new file mode 100644 index 0000000..67ab15d --- /dev/null +++ b/inc/adsp_current_process1.h @@ -0,0 +1,109 @@ +/** + * 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_CURRENT_PROCESS1_H +#define _ADSP_CURRENT_PROCESS1_H +#include "remote.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +#define _const_adsp_current_process1_handle 4 +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, <interface>_URI"&_dom=aDSP" + * <interface>_URI is a QAIC generated uri, or + * "file:///<sofilename>?<interface>_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_exit)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_thread_exit)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_set_logging_params)(remote_handle64 _h, unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_getASID)(remote_handle64 _h, unsigned int* asid) __QAIC_HEADER_ATTRIBUTE; +#ifndef adsp_current_process1_URI +#define adsp_current_process1_URI "file:///libadsp_current_process1_skel.so?adsp_current_process1_skel_handle_invoke&_modver=1.0" +#endif /*adsp_current_process1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS1_H diff --git a/inc/adsp_default_listener.h b/inc/adsp_default_listener.h new file mode 100644 index 0000000..e4353d1 --- /dev/null +++ b/inc/adsp_default_listener.h @@ -0,0 +1,62 @@ +/** + * 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_H +#define _ADSP_DEFAULT_LISTENER_H +#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 +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_default_listener_register)(void) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_DEFAULT_LISTENER_H diff --git a/inc/adsp_listener.h b/inc/adsp_listener.h new file mode 100644 index 0000000..dd05eec --- /dev/null +++ b/inc/adsp_listener.h @@ -0,0 +1,77 @@ +/** + * 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_H +#define _ADSP_LISTENER_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +#define _const_adsp_listener_handle 3 +typedef struct _adsp_listener_buffer__seq_uint8 _adsp_listener_buffer__seq_uint8; +typedef _adsp_listener_buffer__seq_uint8 adsp_listener_buffer; +struct _adsp_listener_buffer__seq_uint8 { + uint8* data; + int dataLen; +}; +typedef uint32 adsp_listener_remote_handle; +typedef uint32 adsp_listener_invoke_ctx; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(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_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_invoke_get_in_bufs)(adsp_listener_invoke_ctx ctx, adsp_listener_buffer* inBuffers, int inBuffersLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_init)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_init2)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(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_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_get_in_bufs2)(adsp_listener_invoke_ctx ctx, int offset, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_LISTENER_H diff --git a/inc/adsp_perf.h b/inc/adsp_perf.h new file mode 100644 index 0000000..d2ce8a0 --- /dev/null +++ b/inc/adsp_perf.h @@ -0,0 +1,109 @@ +/** + * 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_H +#define _ADSP_PERF_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +/** + * Interface for querying the adsp for counter data + * For example, to enable all the perf numbers: + * + * int perf_on(void) { + * int nErr = 0; + * int numKeys = 0, maxLen = 0, ii; + * char keys[512]; + * char* buf = &keys[0]; + * VERIFY(0 == adsp_perf_get_keys(keys, 512, &maxLen, &numKeys)); + * assert(maxLen < 512); + * for(ii = 0; ii < numKeys; ++ii) { + * char* name = buf; + * buf += strlen(name) + 1; + * printf("perf on: %s\n", name); + * VERIFY(0 == adsp_perf_enable(ii)); + * } + * bail: + * return nErr; + * } + * + * To read all the results: + * + * int rpcperf_perf_result(void) { + * int nErr = 0; + * int numKeys, maxLen, ii; + * char keys[512]; + * char* buf = &keys[0]; + * long long usecs[16]; + * VERIFY(0 == adsp_perf_get_keys(keys, 512, &maxLen, &numKeys)); + * printf("perf keys: %d\n", numKeys); + * VERIFY(0 == adsp_perf_get_usecs(usecs, 16)); + * assert(maxLen < 512); + * assert(numKeys < 16); + * for(ii = 0; ii < numKeys; ++ii) { + * char* name = buf; + * buf += strlen(name) + 1; + * printf("perf result: %s %lld\n", name, usecs[ii]); + * } + * bail: + * return nErr; + * } + */ +#define _const_adsp_perf_handle 6 +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf_enable)(int ix) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf_get_usecs)(int64* dst, int dstLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf_get_keys)(char* keys, int keysLen, int* maxLen, int* numKeys) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_PERF_H diff --git a/inc/adsp_pls.h b/inc/adsp_pls.h new file mode 100644 index 0000000..e21679d --- /dev/null +++ b/inc/adsp_pls.h @@ -0,0 +1,98 @@ +/** + * 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_PLS_H +#define ADSP_PLS_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif +/** + * internal header + */ + +/** + * adsp process local storage is local storage for the fastrpc hlos + * process context. + + * When used from within a fastrpc started thread this will attach + * desturctors to the lifetime of the hlos process that is making the + * rpc calls. Users can use this to store context for the lifetime of + * the calling process on the hlos. + */ + +/** + * adds a new key to the local storage, overriding + * any previous value at the key. Overriding the key + * does not cause the destructor to run. + * + * @param type, type part of the key to be used for lookup, + * these should be static addresses, like the address of a function. + * @param key, the key to be used for lookup + * @param size, the size of the data + * @param ctor, constructor that takes a context and memory of size + * @param ctx, constructor context passed as the first argument to ctor + * @param dtor, destructor to run at pls shutdown + * @param ppo, output data + * @retval, 0 for success + */ +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); + +/** + * Like add, but will only add 1 item, and return the same item on the + * next add. If two threads try to call this function at teh same time + * they will both receive the same value as a result, but the constructors + * may be called twice. + * item if its already there, otherwise tries to add. + * ctor may be called twice + * callers should avoid calling pls_add which will override the singleton + */ +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); + +/** + * finds the last data pointer added for key to the local storage + * + * @param key, the key to be used for lookup + * @param ppo, output data + * @retval, 0 for success + */ +int adsp_pls_lookup(uintptr_t type, uintptr_t key, void** ppo); + +/** + * force init/deinit + */ +int gpls_init(void); +void gpls_deinit(void); + +#ifdef __cplusplus +} +#endif +#endif //ADSP_PLS_H diff --git a/inc/adspmsgd_adsp.h b/inc/adspmsgd_adsp.h new file mode 100644 index 0000000..b9094bd --- /dev/null +++ b/inc/adspmsgd_adsp.h @@ -0,0 +1,65 @@ +/** + * 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_H +#define _ADSPMSGD_ADSP_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp_init)(int heapid, uint32 ion_flags, uint32 filter, uint32 buf_size, int* buff_addr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp_init2)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp_deinit)(void) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP_H diff --git a/inc/adspmsgd_adsp1.h b/inc/adspmsgd_adsp1.h new file mode 100644 index 0000000..1166004 --- /dev/null +++ b/inc/adspmsgd_adsp1.h @@ -0,0 +1,99 @@ +/** + * 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_ADSP1_H +#define _ADSPMSGD_ADSP1_H +#include "AEEStdDef.h" +#include "remote.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +#define _const_adspmsgd_adsp1_handle 5 +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, <interface>_URI"&_dom=aDSP" + * <interface>_URI is a QAIC generated uri, or + * "file:///<sofilename>?<interface>_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_init2)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_deinit)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +#ifndef adspmsgd_adsp1_URI +#define adspmsgd_adsp1_URI "file:///libadspmsgd_adsp1_skel.so?adspmsgd_adsp1_skel_handle_invoke&_modver=1.0" +#endif /*adspmsgd_adsp1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP1_H diff --git a/inc/adspmsgd_apps.h b/inc/adspmsgd_apps.h new file mode 100644 index 0000000..64db95d --- /dev/null +++ b/inc/adspmsgd_apps.h @@ -0,0 +1,78 @@ +/** + * 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_H +#define _ADSPMSGD_APPS_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +enum adspmsgd_apps_Level { + LOW, + MEDIUM, + HIGH, + ERROR, + FATAL, + _32BIT_PLACEHOLDER_adspmsgd_apps_Level = 0x7fffffff +}; +typedef enum adspmsgd_apps_Level adspmsgd_apps_Level; +typedef struct _adspmsgd_apps_octetSeq__seq_octet _adspmsgd_apps_octetSeq__seq_octet; +typedef _adspmsgd_apps_octetSeq__seq_octet adspmsgd_apps_octetSeq; +struct _adspmsgd_apps_octetSeq__seq_octet { + unsigned char* data; + int dataLen; +}; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_apps_log)(const unsigned char* log_message_buffer, int log_message_bufferLen) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_APPS_H diff --git a/inc/apps_mem.h b/inc/apps_mem.h new file mode 100644 index 0000000..12f7001 --- /dev/null +++ b/inc/apps_mem.h @@ -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. + */ + +#ifndef _APPS_MEM_H +#define _APPS_MEM_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_map)(int heapid, uint32 ion_flags, uint32 rflags, uint32 vin, int32 len, uint32* vapps, uint32* vadsp) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_unmap)(uint32 vadsp, int32 len) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_map64)(int heapid, uint32 ion_flags, uint32 rflags, uint64 vin, int64 len, uint64* vapps, uint64* vadsp) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_unmap64)(uint64 vadsp, int64 len) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_share_map)(int fd, int size, uint64* vapps, uint64* vadsp) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_share_unmap)(uint64 vadsp, int size) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_APPS_MEM_H diff --git a/inc/apps_remotectl.h b/inc/apps_remotectl.h new file mode 100644 index 0000000..34f1692 --- /dev/null +++ b/inc/apps_remotectl.h @@ -0,0 +1,73 @@ +/** + * 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_H +#define _APPS_REMOTECTL_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_remotectl_open)(const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_remotectl_close)(int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_APPS_REMOTECTL_H diff --git a/inc/apps_std.h b/inc/apps_std.h new file mode 100644 index 0000000..e68a24b --- /dev/null +++ b/inc/apps_std.h @@ -0,0 +1,208 @@ +/** + * 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_STD_H +#define _APPS_STD_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +/** + * standard library functions remoted from the apps to the dsp + */ +typedef int apps_std_FILE; +enum apps_std_SEEK { + APPS_STD_SEEK_SET, + APPS_STD_SEEK_CUR, + APPS_STD_SEEK_END, + _32BIT_PLACEHOLDER_apps_std_SEEK = 0x7fffffff +}; +typedef enum apps_std_SEEK apps_std_SEEK; +typedef struct apps_std_DIR apps_std_DIR; +struct apps_std_DIR { + uint64 handle; +}; +typedef struct apps_std_DIRENT apps_std_DIRENT; +struct apps_std_DIRENT { + int ino; + char name[255]; +}; +typedef struct apps_std_STAT apps_std_STAT; +struct apps_std_STAT { + uint64 tsz; + uint64 dev; + uint64 ino; + uint32 mode; + uint32 nlink; + uint64 rdev; + uint64 size; + int64 atime; + int64 atimensec; + int64 mtime; + int64 mtimensec; + int64 ctime; + int64 ctimensec; +}; +/** + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fopen)(const char* name, const char* mode, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_freopen)(apps_std_FILE sin, const char* name, const char* mode, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fflush)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fclose)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +/** + * @param, bEOF, if read or write bytes <= bufLen bytes then feof() is called + * and the result is returned in bEOF, otherwise bEOF is set to 0. + * @retval, if read or write return 0 for non zero length buffers, ferror is checked + * and a non zero value is returned in case of error with no rout parameters + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fread)(apps_std_FILE sin, byte* buf, int bufLen, int* bytesRead, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fwrite)(apps_std_FILE sin, const byte* buf, int bufLen, int* bytesWritten, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +/** + * @param, pos, this buffer is filled up to MIN(posLen, sizeof(fpos_t)) + * @param, posLenReq, returns sizeof(fpos_t) + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fgetpos)(apps_std_FILE sin, byte* pos, int posLen, int* posLenReq) __QAIC_HEADER_ATTRIBUTE; +/** + * @param, if size of pos doesn't match the system size an error is returned. + * fgetpos can be used to query the size of fpos_t + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fsetpos)(apps_std_FILE sin, const byte* pos, int posLen) __QAIC_HEADER_ATTRIBUTE; +/** + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_ftell)(apps_std_FILE sin, int* pos) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fseek)(apps_std_FILE sin, int offset, apps_std_SEEK whence) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_flen)(apps_std_FILE sin, uint64* len) __QAIC_HEADER_ATTRIBUTE; +/** + * @retval, only fails if transport fails + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_rewind)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_feof)(apps_std_FILE sin, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_ferror)(apps_std_FILE sin, int* err) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_clearerr)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_print_string)(const char* str) __QAIC_HEADER_ATTRIBUTE; +/** + * @param val, must contain space for NULL + * @param valLenReq, length required with NULL + * @retval, if fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_getenv)(const char* name, char* val, int valLen, int* valLenReq) __QAIC_HEADER_ATTRIBUTE; +/** + * @retval, if fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_setenv)(const char* name, const char* val, int override) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_unsetenv)(const char* name) __QAIC_HEADER_ATTRIBUTE; +/** + * This function will try to open a file given directories in envvarname separated by + * delim. + * so given environment variable FOO_PATH=/foo;/bar + * fopen_wth_env("FOO_PATH", ";", "path/to/file", "rw", &out); + * will try to open /foo/path/to/file, /bar/path/to/file + * if the variable is unset, it will open the file directly + * + * @param envvarname, name of the environment variable containing the path + * @param delim, delimiator string, such as ";" + * @param name, name of the file + * @param mode, mode + * @param psout, output handle + * @retval, 0 on success errno or -1 on failure + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fopen_with_env)(const char* envvarname, const char* delim, const char* name, const char* mode, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fgets)(apps_std_FILE sin, byte* buf, int bufLen, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +/** + * This method will return the paths that are searched when looking for a file. + * The paths are defined by the environment variable (separated by delimiters) + * that is passed to the method. + * + * @param envvarname, name of the environment variable containing the path + * @param delim, delimiator string, such as ";" + * @param name, name of the file + * @param paths, Search paths + * @param numPaths, Actual number of paths found + * @param maxPathLen, The max path length + * @retval, 0 on success errno or -1 on failure + * + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_get_search_paths_with_env)(const char* envvarname, const char* delim, _cstring1_t* paths, int pathsLen, uint32* numPaths, uint16* maxPathLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fileExists)(const char* path, boolean* exists) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fsync)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fremove)(const char* name) __QAIC_HEADER_ATTRIBUTE; +/** + * This function decrypts the file using the provided open file descriptor, closes the + * original descriptor and return a new file descriptor. + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fdopen_decrypt)(apps_std_FILE sin, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_opendir)(const char* name, apps_std_DIR* dir) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_closedir)(const apps_std_DIR* dir) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_readdir)(const apps_std_DIR* dir, apps_std_DIRENT* dirent, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_mkdir)(const char* name, int mode) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_rmdir)(const char* name) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_stat)(const char* name, apps_std_STAT* stat) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_ftrunc)(apps_std_FILE sin, int offset) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_frename)(const char* oldname, const char* newname) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_APPS_STD_H diff --git a/inc/fastrpc_apps_user.h b/inc/fastrpc_apps_user.h new file mode 100644 index 0000000..46c5614 --- /dev/null +++ b/inc/fastrpc_apps_user.h @@ -0,0 +1,65 @@ +/** + * 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 FASTRPC_ANDROID_USER_H +#define FASTRPC_ANDROID_USER_H + +#include <assert.h> +#include <fcntl.h> +#include <asm/ioctl.h> +#include <errno.h> + +/* + * API to check if kernel supports remote memory allocation + * Returns 0 if NOT supported + * + */ +int is_kernel_alloc_supported(int dev, int domain); + +/* + * API to allocate ION memory for internal purposes + * Returns NULL if allocation fails + * + */ +void* rpcmem_alloc_internal(int heapid, uint32 flags, int size); + +/* + * API to free internally allocated ION memory + * + */ +void rpcmem_free_internal(void* po); + +/* + * API to get fd of internally allocated ION buffer + * Returns valid fd on success and -1 on failure + * + */ +int rpcmem_to_fd_internal(void *po); + +#endif //FASTRPC_ANDROID_USER_H diff --git a/inc/fastrpc_internal.h b/inc/fastrpc_internal.h new file mode 100644 index 0000000..8cb57a2 --- /dev/null +++ b/inc/fastrpc_internal.h @@ -0,0 +1,308 @@ +/** + * 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 FASTRPC_INTERNAL_H +#define FASTRPC_INTERNAL_H + +#include <linux/types.h> +#include "remote64.h" +#include "verify.h" +#include "AEEstd.h" + +#define FASTRPC_IOCTL_ALLOC_DMA_BUFF _IOWR('R', 1, struct fastrpc_alloc_dma_buf) +#define FASTRPC_IOCTL_FREE_DMA_BUFF _IOWR('R', 2, uint32_t) +#define FASTRPC_IOCTL_INVOKE _IOWR('R', 3, struct fastrpc_invoke) +#define FASTRPC_IOCTL_INIT_ATTACH _IO('R', 4) +#define FASTRPC_IOCTL_INIT_CREATE _IOWR('R', 5, struct fastrpc_init_create) +#define FASTRPC_IOCTL_MMAP _IOWR('R', 6, struct fastrpc_ioctl_mmap) +#define FASTRPC_IOCTL_MUNMAP _IOWR('R', 7, struct fastrpc_ioctl_munmap) + + +#define DEVICE_NAME "adsprpc-smd" + +#if !(defined __qdsp6__) && !(defined __hexagon__) +static __inline uint32 Q6_R_cl0_R(uint32 num) { + int ii; + for(ii = 31; ii >= 0; --ii) { + if(num & (1 << ii)) { + return 31 - ii; + } + } + return 0; +} +#else +#include "hexagon_protos.h" +#include <types.h> +#endif + +#define FASTRPC_INFO_SMMU (1 << 0) + +/* struct fastrpc_invoke_args { + __u64 ptr; + __u64 length; + __s32 fd; + __u32 attrs; + __u32 crc; +}; */ + +struct fastrpc_invoke_args { + __u64 ptr; + __u64 length; + __s32 fd; + __u32 reserved; +}; + +struct fastrpc_invoke { + __u32 handle; + __u32 sc; + __u64 args; +}; + +#define FASTRPC_ATTR_NOVA (1) +#define FASTRPC_ATTR_NOMAP (16) + +#define GUEST_OS 0 +#define USER_PD -1 +#define STATIC_USER_PD 1 +#define ATTACH_SENSORS_PD 2 +#define GUEST_OS_SHARED 3 + +struct fastrpc_init_create { + __u32 filelen; /* elf file length */ + __s32 filefd; /* fd for the file */ + __u32 attrs; + __u32 siglen; + __u64 file; /* pointer to elf file */ +}; + +#define FASTRPC_ATTR_DEBUG_PROCESS (1) + +struct fastrpc_alloc_dma_buf { + __s32 fd; /* fd */ + __u32 flags; /* flags to map with */ + __u64 size; /* size */ +}; + +struct fastrpc_ioctl_mmap { + __s32 fd; /* fd */ + __u32 flags; /* flags for dsp to map with */ + __u64 vaddrin; /* optional virtual address */ + __u64 size; /* size */ + __u64 vaddrout; /* dsps virtual address */ +}; + +struct fastrpc_ioctl_munmap { + __u64 vaddrout; /* address to unmap */ + __u64 size; /* size */ +}; + +#define FASTRPC_CONTROL_LATENCY (1) +struct fastrpc_ctrl_latency { + uint32_t enable; //!latency control enable + uint32_t level; //!level of control +}; +#define FASTRPC_CONTROL_SMMU (2) +struct fastrpc_ctrl_smmu { + uint32_t sharedcb; +}; + +#define FASTRPC_CONTROL_KALLOC (3) +struct fastrpc_ctrl_kalloc { + uint32_t kalloc_support; +}; + +struct fastrpc_ioctl_control { + uint32_t req; + union { + struct fastrpc_ctrl_latency lp; + struct fastrpc_ctrl_smmu smmu; + struct fastrpc_ctrl_kalloc kalloc; + }; +}; + +#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp" + +struct smq_null_invoke32 { + uint32_t ctx; //! invoke caller context + remote_handle handle; //! handle to invoke + uint32_t sc; //! scalars structure describing the rest of the data +}; + +struct smq_null_invoke { + uint64_t ctx; //! invoke caller context + remote_handle handle; //! handle to invoke + uint32_t sc; //! scalars structure describing the rest of the data +}; + +typedef uint32_t smq_invoke_buf_phy_addr; + +struct smq_phy_page { + uint64_t addr; //! physical address + int64_t size; //! size +}; + +struct smq_phy_page32 { + uint32_t addr; //! physical address + uint32_t size; //! size +}; + +struct smq_invoke_buf { + int num; + int pgidx; +}; + +struct smq_invoke32 { + struct smq_null_invoke32 header; + struct smq_phy_page32 page; //! remote arg and list of pages address +}; + +struct smq_invoke { + struct smq_null_invoke header; + struct smq_phy_page page; //! remote arg and list of pages address +}; + +struct smq_msg32 { + uint32_t pid; + uint32_t tid; + struct smq_invoke32 invoke; +}; + +struct smq_msg { + uint32_t pid; + uint32_t tid; + struct smq_invoke invoke; +}; + +struct smq_msg_u { + union { + struct smq_msg32 msg32; + struct smq_msg msg64; + } msg; + int size; +}; + +struct smq_invoke_rsp32 { + uint32_t ctx; //! invoke caller context + int nRetVal; //! invoke return value +}; + +struct smq_invoke_rsp { + uint64_t ctx; //! invoke caller context + int nRetVal; //! invoke return value +}; + +struct smq_invoke_rsp_u { + union { + struct smq_invoke_rsp32 rsp32; + struct smq_invoke_rsp rsp64; + } rsp; + int size; +}; + +static __inline void to_smq_msg(uint32 mode, struct smq_msg_u* msg, struct smq_msg* msg64) { + if(0 == mode) { + msg64->pid = msg->msg.msg32.pid; + msg64->tid = msg->msg.msg32.tid; + msg64->invoke.header.ctx = msg->msg.msg32.invoke.header.ctx; + msg64->invoke.header.handle = msg->msg.msg32.invoke.header.handle; + msg64->invoke.header.sc = msg->msg.msg32.invoke.header.sc; + msg64->invoke.page.addr = msg->msg.msg32.invoke.page.addr; + msg64->invoke.page.size = msg->msg.msg32.invoke.page.size; + } else { + std_memmove(msg64, &msg->msg.msg64, sizeof(*msg64)); + } +} + +static __inline void to_smq_invoke_rsp(uint32 mode, uint64 ctx, int nRetVal, struct smq_invoke_rsp_u* rsp) { + if (0 == mode) { + rsp->rsp.rsp32.ctx = (uint32)ctx; + rsp->rsp.rsp32.nRetVal = nRetVal; + rsp->size = sizeof(rsp->rsp.rsp32); + } else { + rsp->rsp.rsp64.ctx = ctx; + rsp->rsp.rsp64.nRetVal = nRetVal; + rsp->size = sizeof(rsp->rsp.rsp64); + } +} + +static __inline struct smq_invoke_buf* to_smq_invoke_buf_start(uint32 mode, void* virt, uint32 sc) { + struct smq_invoke_buf* buf; + int len = REMOTE_SCALARS_LENGTH(sc); + if(0 == mode) { + remote_arg* pra = (remote_arg*)virt; + buf = (struct smq_invoke_buf*)(&pra[len]); + } else { + remote_arg64* pra = (remote_arg64*)virt; + buf = (struct smq_invoke_buf*)(&pra[len]); + } + return buf; +} + +static __inline struct smq_invoke_buf* smq_invoke_buf_start(remote_arg64 *pra, uint32 sc) { + int len = REMOTE_SCALARS_LENGTH(sc); + return (struct smq_invoke_buf*)(&pra[len]); +} + +static __inline struct smq_phy_page* smq_phy_page_start(uint32 sc, struct smq_invoke_buf* buf) { + int nTotal = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc); + return (struct smq_phy_page*)(&buf[nTotal]); +} + +//! size of the out of band data +static __inline int smq_data_size(uint32 sc, int nPages) { + struct smq_invoke_buf* buf = smq_invoke_buf_start(0, sc); + struct smq_phy_page* page = smq_phy_page_start(sc, buf); + return (int)(uintptr_t)(&(page[nPages])); +} + +static __inline void to_smq_data(uint32 mode, uint32 sc, int nPages, void* pv, remote_arg64* rpra) { + if(0 == mode) { + struct smq_phy_page* page; + struct smq_phy_page32* page32; + remote_arg *pra = (remote_arg*)pv; + int ii, len; + len = REMOTE_SCALARS_LENGTH(sc); + for(ii = 0; ii < len; ++ii) { + rpra[ii].buf.pv = (uint64)(uintptr_t)pra[ii].buf.pv; + rpra[ii].buf.nLen = pra[ii].buf.nLen; + } + len = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc); + std_memmove(&rpra[ii], &pra[ii], len * sizeof(struct smq_invoke_buf)); + page = (struct smq_phy_page*)((struct smq_invoke_buf*)&rpra[ii] + len); + page32 = (struct smq_phy_page32*)((struct smq_invoke_buf*)&pra[ii] + len); + for(ii = 0; ii < nPages; ++ii) { + page[ii].addr = page32[ii].addr; + page[ii].size = page32[ii].size; + } + } else { + std_memmove(rpra, pv, smq_data_size(sc, nPages)); + } +} + +#endif // FASTRPC_INTERNAL_H diff --git a/inc/fastrpc_perf.h b/inc/fastrpc_perf.h new file mode 100644 index 0000000..ab0deaa --- /dev/null +++ b/inc/fastrpc_perf.h @@ -0,0 +1,60 @@ +/** + * 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 FASTRPC_PERF_H +#define FASTRPC_PERF_H + +#include "remote.h" +#ifdef __ANDROID__ +#include "cutils/properties.h" +#else +#define PROPERTY_VALUE_MAX 32 +#endif + +#if (defined LE_ENABLE) +#define FASTRPC_PROPERTY_GET_INT32(key, defvalue) ((int)0) +#define FASTRPC_PROPERTY_GET_STR(key, buffer, defvalue) ((int)0) +#else +#if (defined __ANDROID__) +#define FASTRPC_PROPERTY_GET_INT32(key, defvalue) ((int)property_get_int32((key), (defvalue))) +#define FASTRPC_PROPERTY_GET_STR(key, buffer, defvalue) ((int)property_get((key), (buffer), (defvalue))) +#else +#define FASTRPC_PROPERTY_GET_INT32(key, defvalue) ((int)0) +#define FASTRPC_PROPERTY_GET_STR(key, buffer, defvalue) ((int)0) +#endif +#endif + +#define FASTRPC_MAX_STATIC_HANDLE (10) +#define IS_STATIC_HANDLE(handle) ((handle) >= 0 && (handle) <= FASTRPC_MAX_STATIC_HANDLE) +extern int fastrpc_perf_init(int dev); +extern void fastrpc_perf_update(int dev, remote_handle handle, uint32_t sc); +extern void fastrpc_perf_deinit(void); + +#endif //FASTRPC_PERF_H diff --git a/inc/listener_android.h b/inc/listener_android.h new file mode 100644 index 0000000..bd76984 --- /dev/null +++ b/inc/listener_android.h @@ -0,0 +1,49 @@ +/** + * 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 LISTENER_ANDROID_H +#define LISTENER_ANDROID_H + +#include <pthread.h> +#include <dlfcn.h> +#include "pthread_rw_mutex.h" + +#define MSG(a, b, c) printf(__FILE_LINE__ ":" c ) +#define MSG_1(a, b, c, d) printf(__FILE_LINE__ ":" c , d) +#define MSG_2(a, b, c, d, e) printf(__FILE_LINE__ ":" c , d, e) +#define MSG_3(a, b, c, d, e, f) printf(__FILE_LINE__ ":" c , d, e, f) +#define MSG_4(a, b, c, d, e, f,g) printf(__FILE_LINE__ ":" c , d, e, f, g) + +#define DLW_RTLD_NOW RTLD_NOW +#define dlw_Open dlopen +#define dlw_Sym dlsym +#define dlw_Close dlclose +#define dlw_Error dlerror + +#endif diff --git a/inc/listener_buf.h b/inc/listener_buf.h new file mode 100644 index 0000000..ee95b1d --- /dev/null +++ b/inc/listener_buf.h @@ -0,0 +1,124 @@ +/** + * 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 LISTENER_BUF_H +#define LISTENER_BUF_H + +#include "sbuf.h" +#include "remote.h" +#include "verify.h" + +static __inline void pack_in_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + len = (uint32_t)pra[ii].buf.nLen; + sbuf_write(buf, (uint8*)&len, 4); + if(len) { + sbuf_align(buf, 8); + sbuf_write(buf, pra[ii].buf.pv, len); + } + } +} + +static __inline void pack_out_lens(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + len = (uint32_t)pra[ii].buf.nLen; + sbuf_write(buf, (uint8*)&len, 4); + } +} + +static __inline void unpack_in_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len=0; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + sbuf_read(buf, (uint8*)&len, 4); + pra[ii].buf.nLen = len; + if(pra[ii].buf.nLen) { + sbuf_align(buf, 8); + if((int)pra[ii].buf.nLen <= sbuf_left(buf)) { + pra[ii].buf.pv = sbuf_head(buf); + } + sbuf_advance(buf, pra[ii].buf.nLen); + } + } +} + +static __inline void unpack_out_lens(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len=0; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + sbuf_read(buf, (uint8*)&len, 4); + pra[ii].buf.nLen = len; + } +} + +//map out buffers on the hlos side to the remote_arg array +//dst is the space required for buffers we coun't map from the adsp +static __inline void pack_out_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + len = (uint32_t)pra[ii].buf.nLen; + sbuf_write(buf, (uint8*)&len, 4); + if(pra[ii].buf.nLen) { + sbuf_align(buf, 8); + if((int)pra[ii].buf.nLen <= sbuf_left(buf)) { + pra[ii].buf.pv = sbuf_head(buf); + } + sbuf_advance(buf, pra[ii].buf.nLen); + } + } +} + +//on the aDSP copy the data from buffers we had to copy to the local remote_arg structure +static __inline int unpack_out_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii, nErr = 0; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + sbuf_read(buf, (uint8*)&len, 4); + VERIFY(len == pra[ii].buf.nLen); + if(pra[ii].buf.nLen) { + sbuf_align(buf, 8); + sbuf_read(buf, pra[ii].buf.pv, pra[ii].buf.nLen); + } + } +bail: + return nErr; +} + +#endif diff --git a/inc/mod_table.h b/inc/mod_table.h new file mode 100644 index 0000000..9e4e219 --- /dev/null +++ b/inc/mod_table.h @@ -0,0 +1,138 @@ +/** + * 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 MOD_TABLE_H +#define MOD_TABLE_H + +#include "remote64.h" +#include "AEEStdDef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * multi-domain support + * + * multi domain modules return remote_handl64 on open/close, but mod_table + * creates uint32 handles as the "remote" facing handle. These fit nicely + * into the transport layer. + * + */ + +/** + * 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)); + +/** + * same as register_static, but module with user defined handle lifetimes. + */ +int mod_table_register_static1(const char* uri, int (*pfn)(remote_handle64 h,uint32 sc, remote_arg* pra)); + +/** + * 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. This api should only be use by system components + * that will never be upgradable. + * + * 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)); + +/** + * same as register_static, but module with user defined handle lifetimes. + */ +int mod_table_register_static_override1(const char* uri, int(*pfn)(remote_handle64,uint32 sc, remote_arg* pra)); + +/** + * Open a module and get a handle to it + * + * in_name, 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* in_name, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr); + +/** + * 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); + +/** + * 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); + +/** + * internal use only + */ +int mod_table_register_const_handle(remote_handle handle, const char* in_name, int (*pfn)(uint32 sc, remote_arg* pra)); +/** + * @param remote, the handle we should expect from the transport layer + * @param local, the local handle that will be passed to pfn + */ +int mod_table_register_const_handle1(remote_handle remote, remote_handle64 local, const char* uri, int (*pfn)(remote_handle64 h, uint32 sc, remote_arg* pra)); + +#ifdef __cplusplus +} +#endif + +#endif // MOD_TABLE_H diff --git a/inc/mutex.h b/inc/mutex.h new file mode 100644 index 0000000..a318c44 --- /dev/null +++ b/inc/mutex.h @@ -0,0 +1,105 @@ +#ifndef MUTEX_H +#define MUTEX_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. + */ + +#if (defined __qdsp6__) || (defined __hexagon__) +#include "qurt_mutex.h" + +#define RW_MUTEX_T qurt_mutex_t +#define RW_MUTEX_CTOR(mut) qurt_mutex_init(& (mut)) +#define RW_MUTEX_LOCK_READ(mut) qurt_mutex_lock(& (mut)) +#define RW_MUTEX_UNLOCK_READ(mut) qurt_mutex_unlock(& (mut)) +#define RW_MUTEX_LOCK_WRITE(mut) qurt_mutex_lock(& (mut)) +#define RW_MUTEX_UNLOCK_WRITE(mut) qurt_mutex_unlock(& (mut)) +#define RW_MUTEX_DTOR(mut) qurt_mutex_destroy(& (mut)) + +#elif (1 == __linux) || (1 == __linux__) || (1 == __gnu_linux__) || (1 == linux) + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> + +/* asserts may be compiled out, this should always be present */ +#define ABORT_FAIL( ff ) \ + do {\ + if(! (ff) ) {\ + fprintf(stderr, "assertion \"%s\" failed: file \"%s\", line %d\n", #ff, __FILE__, __LINE__);\ + abort();\ + }\ + } while(0) + +#define RW_MUTEX_T pthread_rwlock_t +#define RW_MUTEX_CTOR(mut) ABORT_FAIL(0 == pthread_rwlock_init( & (mut), 0)) +#define RW_MUTEX_LOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_rdlock( & (mut))) +#define RW_MUTEX_UNLOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) +#define RW_MUTEX_LOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_wrlock( & (mut))) +#define RW_MUTEX_UNLOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) +#define RW_MUTEX_DTOR(mut) ABORT_FAIL(0 == pthread_rwlock_destroy( & (mut))) + + +#else + +#include "AEEstd.h" + +#define RW_MUTEX_T uint32 +#define RW_MUTEX_CTOR(mut) mut = 0 +#define RW_MUTEX_LOCK_READ(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1) == 0); \ + assert(STD_BIT_TEST(&mut, 2) == 0); \ + STD_BIT_SET(&mut, 1); \ + } while (0) + +#define RW_MUTEX_UNLOCK_READ(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1)); \ + assert(STD_BIT_TEST(&mut, 2) == 0); \ + STD_BIT_CLEAR(&mut, 1); \ + } while (0) + +#define RW_MUTEX_LOCK_WRITE(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1) == 0); \ + assert(STD_BIT_TEST(&mut, 2) == 0); \ + STD_BIT_SET(&mut, 2); \ + } while (0) + +#define RW_MUTEX_UNLOCK_WRITE(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1) == 0); \ + assert(STD_BIT_TEST(&mut, 2)); \ + STD_BIT_CLEAR(&mut, 2); \ + } while (0) + +#define RW_MUTEX_DTOR(mut) mut = 0 + +#endif +#endif //MUTEX_H diff --git a/inc/platform_libs.h b/inc/platform_libs.h new file mode 100644 index 0000000..fc6c751 --- /dev/null +++ b/inc/platform_libs.h @@ -0,0 +1,182 @@ +#ifndef PLATFORM_LIBS_H +#define PLATFORM_LIBS_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. + */ + +/* +Platfrom Library Loader +----------------------- + +proj/platform_libs is a library to help manage interdependencies between +other libraries. + + +to use you will need to add + +incs = { 'proj/platform_libs' } + +in source of the library implementation define the entry point + +#include "platform_libs.h" +PL_DEFINE(svfs, svfs_init, svfs_deinit); + +Platfrom Library List +--------------------- + +This list contains top level libraries to be initialized at boot. To make +sure that this library is loaded you would need to call PLRegister or +PLRegisterDefault in your scons build command. + + +Handling Interdependencies and Order +------------------------------------ + +To make sure that library A is loaded before library B, library B's +constructor and destructor should initialize and cleanup libraryB. + +#include "platform_libs.h" + +PL_DEP(libraryB) +void libraryA_deinit(void) { + PL_DEINIT(libraryB); +} + +int libraryA_init(void) { + int nErr = 0; + // my init code + VERIFY(0 == PL_INIT(libraryB)); +bail: + if(nErr) { libraryA_deinit() } + return nErr; +} + + +libraryB does not need to appear in the platform library list. +*/ + +#include <stdint.h> + +struct platform_lib { + const char* name; + uint32_t uRefs; + int nErr; + int (*init)(void); + void (*deinit)(void); +}; + +/** + * use this macro to pull in external dependencies + */ +#ifdef __cplusplus +#define PL_DEP(name)\ + extern "C" {\ + extern struct platform_lib* _pl_##name(void); \ + } +#else +#define PL_DEP(name)\ + extern struct platform_lib* _pl_##name(void); +#endif /* __cplusplus */ + +/** + * should be declared in source in the library + * if constructor fails, destructor is not called + */ +#ifdef __cplusplus +#define PL_DEFINE(name, init, deinit) \ + extern "C" {\ + struct platform_lib* _pl_##name(void) {\ + static struct platform_lib _gpl_##name = { #name, 0, -1, init, deinit };\ + return &_gpl_##name;\ + }\ + } +#else +#define PL_DEFINE(name, init, deinit) \ + struct platform_lib* _pl_##name(void) {\ + static struct platform_lib _gpl_##name = { #name, 0, -1, init, deinit };\ + return &_gpl_##name;\ + } +#endif /* __cplusplus */ + +/** + * should be added to platform_libs_list.c pl_list table + * for all top level modules + */ +#define PL_ENTRY(name) _pl_##name + +/** + * should be called within a constructor to ensure that a + * dependency has been initialized. so if foo depends on bar + * + * #include "bar.h" + * int foo_init() { + * return PL_INIT(bar); + * } + */ +#define PL_INIT(name) pl_lib_init(PL_ENTRY(name)) + +/** + * should be called within a destructor to ensure that a + * dependency has been cleaned up + */ +#define PL_DEINIT(name) pl_lib_deinit(PL_ENTRY(name)) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * initalize the static list of library constructors and destructors + * should be called from main() + * + * see platform_libs_list.h to add high level libraries + * + */ +int pl_init(void); + +/** + * calls all the destructors. + */ +void pl_deinit(void); + +/** + * initialize a single library. called via PL_INIT + */ +int pl_lib_init(struct platform_lib* (*pl)(void)); + +/** + * deinitialize a single library called via PL_DEINIT + */ +void pl_lib_deinit(struct platform_lib* (*pl)(void)); + +#ifdef __cplusplus +} +#endif + +#endif //PLATFORM_LIBS diff --git a/inc/pls.h b/inc/pls.h new file mode 100644 index 0000000..c832aa9 --- /dev/null +++ b/inc/pls.h @@ -0,0 +1,213 @@ +#ifndef PLS_H +#define PLS_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 <stdlib.h> +#include "AEEStdDef.h" +#include "AEEatomic.h" +#include "verify.h" +#include "HAP_farf.h" + +struct PLS; + +struct plskey { + uintptr_t type; + uintptr_t key; +}; + +struct PLS { + struct PLS* next; + struct plskey key; + void (*dtor)(void* data); + uint64_t data[1]; +}; + + +struct pls_table { + struct PLS* lst; + uint32_t uRefs; + uint32_t primThread; +}; + +/** + * initialize on every thread and stick the pls_thread_deinit + * function into the threads tls + */ +static __inline int pls_thread_init(struct pls_table* me, uintptr_t tid) { + if(tid == me->primThread) { + return 0; + } + if(0 == atomic_CompareOrAdd(&me->uRefs, 0, 1)) { + return -1; + } + return 0; +} + +/* call this constructor before the first thread creation with the + * first threads id + */ +static __inline void pls_ctor(struct pls_table* me, uintptr_t primThread) { + me->uRefs = 1; + me->primThread = primThread; +} + +static __inline struct pls_table* pls_thread_deinit(struct pls_table* me) { + if(me && 0 != me->uRefs && 0 == atomic_Add(&me->uRefs, -1)) { + struct PLS* lst, *next; + lst = me->lst; + me->lst = 0; + while(lst) { + next = lst->next; + if(lst->dtor) { + FARF(HIGH, "pls dtor %p", lst->dtor); + lst->dtor((void*)lst->data); + } + free(lst); + lst = next; + } + return me; + } + return 0; +} + +/** + * adds a new key to the local storage, overriding + * any previous value at the key. Overriding the key + * does not cause the destructor to run. + * + * @param type, type part of the key to be used for lookup, + these should be static addresses. + * @param key, the key to be used for lookup + * @param size, the size of the data + * @param ctor, constructor that takes a context and memory of size + * @param ctx, constructor context passed as the first argument to ctor + * @param dtor, destructor to run at pls shutdown + * @param ppo, output data + * @retval, 0 for success + */ + +static __inline int pls_add(struct pls_table* me, uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* data), void** ppo) { + int nErr = 0; + struct PLS* pls = 0; + struct PLS* prev; + VERIFY(me->uRefs != 0); + VERIFY(0 != (pls = (struct PLS*)calloc(1, size + sizeof(*pls) - sizeof(pls->data)))); + if(ctor) { + VERIFY(0 == ctor(ctx, (void*)pls->data)); + } + pls->dtor = dtor; + pls->key.type = type; + pls->key.key = key; + do { + pls->next = me->lst; + prev = (struct PLS*)atomic_CompareAndExchangeUP((uintptr_t*)&me->lst, (uintptr_t)pls, (uintptr_t)pls->next); + } while(prev != pls->next); + if(ppo) { + *ppo = (void*)pls->data; + } + FARF(HIGH, "pls added %p", dtor); +bail: + if(nErr && pls) { + free(pls); + } + return nErr; +} + +static __inline int pls_lookup(struct pls_table* me, uintptr_t type, uintptr_t key, void** ppo); + +/** + * like add, but will only add 1 item if two threads try to add at the same time. returns + * item if its already there, otherwise tries to add. + * ctor may be called twice + * callers should avoid calling pls_add which will override the singleton + */ +static __inline int pls_add_lookup_singleton(struct pls_table* me, uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* data), void** ppo) { + int nErr = 0; + struct PLS* pls = 0; + struct PLS* prev; + if(0 == pls_lookup(me, type, key, ppo)) { + return 0; + } + VERIFY(me->uRefs != 0); + VERIFY(0 != (pls = (struct PLS*)calloc(1, size + sizeof(*pls) - sizeof(pls->data)))); + if(ctor) { + VERIFY(0 == ctor(ctx, (void*)pls->data)); + } + pls->dtor = dtor; + pls->key.type = type; + pls->key.key = key; + do { + pls->next = me->lst; + if(0 == pls_lookup(me, type, key, ppo)) { + if(pls->dtor) { + pls->dtor((void*)pls->data); + } + free(pls); + return 0; + } + prev = (struct PLS*)atomic_CompareAndExchangeUP((uintptr_t*)&me->lst, (uintptr_t)pls, (uintptr_t)pls->next); + } while(prev != pls->next); + if(ppo) { + *ppo = (void*)pls->data; + } + FARF(HIGH, "pls added %p", dtor); +bail: + if(nErr && pls) { + free(pls); + } + return nErr; +} + + +/** + * finds the last data pointer added for key to the local storage + * + * @param key, the key to be used for lookup + * @param ppo, output data + * @retval, 0 for success + */ + +static __inline int pls_lookup(struct pls_table* me, uintptr_t type, uintptr_t key, void** ppo) { + struct PLS* lst; + for(lst = me->lst; me->uRefs != 0 && lst != 0; lst = lst->next) { + if(lst->key.type == type && lst->key.key == key) { + if(ppo) { + *ppo = lst->data; + } + return 0; + } + } + return -1; +} + +#endif //PLS_H + + diff --git a/inc/pthread_rw_mutex.h b/inc/pthread_rw_mutex.h new file mode 100644 index 0000000..61e6278 --- /dev/null +++ b/inc/pthread_rw_mutex.h @@ -0,0 +1,59 @@ +/** + * 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 PTHREAD_RW_MUTEX_H +#define PTHREAD_RW_MUTEX_H + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> + +/* asserts may be compiled out, this should always be present */ +#define ABORT_FAIL( ff ) \ + do {\ + if(! (ff) ) {\ + fprintf(stderr, "assertion \"%s\" failed: file \"%s\", line %d\n", #ff, __FILE__, __LINE__);\ + abort();\ + }\ + } while(0) + +#define RW_MUTEX_T pthread_rwlock_t +#define RW_MUTEX_CTOR(mut) ABORT_FAIL(0 == pthread_rwlock_init( & (mut), 0)) +#define RW_MUTEX_LOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_rdlock( & (mut))) + +#define RW_MUTEX_UNLOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) + +#define RW_MUTEX_LOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_wrlock( & (mut))) + +#define RW_MUTEX_UNLOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) + +#define RW_MUTEX_DTOR(mut) ABORT_FAIL(0 == pthread_rwlock_destroy( & (mut))) + + +#endif //PTHREAD_RW_MUTEX_H diff --git a/inc/remote.h b/inc/remote.h new file mode 100644 index 0000000..8125c2b --- /dev/null +++ b/inc/remote.h @@ -0,0 +1,318 @@ +/** + * 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_H +#define REMOTE_H + +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t remote_handle; +typedef uint64_t remote_handle64; //! used by multi domain modules + //! 64 bit handles are translated to 32 bit values + //! by the transport layer + +typedef struct { + void *pv; + size_t nLen; +} remote_buf; + +typedef struct { + int32_t fd; + uint32_t offset; +} remote_dma_handle; + +typedef union { + remote_buf buf; + remote_handle h; + remote_handle64 h64; //! used by multi domain modules + remote_dma_handle dma; +} remote_arg; + +/*Retrives method attribute from the scalars parameter*/ +#define REMOTE_SCALARS_METHOD_ATTR(dwScalars) (((dwScalars) >> 29) & 0x7) + +/*Retrives method index from the scalars parameter*/ +#define REMOTE_SCALARS_METHOD(dwScalars) (((dwScalars) >> 24) & 0x1f) + +/*Retrives number of input buffers from the scalars parameter*/ +#define REMOTE_SCALARS_INBUFS(dwScalars) (((dwScalars) >> 16) & 0x0ff) + +/*Retrives number of output buffers from the scalars parameter*/ +#define REMOTE_SCALARS_OUTBUFS(dwScalars) (((dwScalars) >> 8) & 0x0ff) + +/*Retrives number of input handles from the scalars parameter*/ +#define REMOTE_SCALARS_INHANDLES(dwScalars) (((dwScalars) >> 4) & 0x0f) + +/*Retrives number of output handles from the scalars parameter*/ +#define REMOTE_SCALARS_OUTHANDLES(dwScalars) ((dwScalars) & 0x0f) + +#define REMOTE_SCALARS_MAKEX(nAttr,nMethod,nIn,nOut,noIn,noOut) \ + ((((uint32_t) (nAttr) & 0x7) << 29) | \ + (((uint32_t) (nMethod) & 0x1f) << 24) | \ + (((uint32_t) (nIn) & 0xff) << 16) | \ + (((uint32_t) (nOut) & 0xff) << 8) | \ + (((uint32_t) (noIn) & 0x0f) << 4) | \ + ((uint32_t) (noOut) & 0x0f)) + +#define REMOTE_SCALARS_MAKE(nMethod,nIn,nOut) REMOTE_SCALARS_MAKEX(0,nMethod,nIn,nOut,0,0) + +#define REMOTE_SCALARS_LENGTH(sc) (REMOTE_SCALARS_INBUFS(sc) +\ + REMOTE_SCALARS_OUTBUFS(sc) +\ + REMOTE_SCALARS_INHANDLES(sc) +\ + REMOTE_SCALARS_OUTHANDLES(sc)) + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_REMOTE_EXPORT +#ifdef _WIN32 +#define __QAIC_REMOTE_EXPORT __declspec(dllexport) +#else //_WIN32 +#define __QAIC_REMOTE_EXPORT +#endif //_WIN32 +#endif //__QAIC_REMOTE_EXPORT + +#ifndef __QAIC_REMOTE_ATTRIBUTE +#define __QAIC_REMOTE_ATTRIBUTE +#endif + +#define NUM_DOMAINS 4 +#define NUM_SESSIONS 2 +#define DOMAIN_ID_MASK 3 + +#ifndef DEFAULT_DOMAIN_ID +#define DEFAULT_DOMAIN_ID 0 +#endif + +#define ADSP_DOMAIN_ID 0 +#define MDSP_DOMAIN_ID 1 +#define SDSP_DOMAIN_ID 2 +#define CDSP_DOMAIN_ID 3 + +#define ADSP_DOMAIN "&_dom=adsp" +#define MDSP_DOMAIN "&_dom=mdsp" +#define SDSP_DOMAIN "&_dom=sdsp" +#define CDSP_DOMAIN "&_dom=cdsp" + +/* All other values are reserved */ + +/* opens a remote_handle "name" + * returns 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_open)(const char* name, remote_handle *ph) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_open)(const char* name, remote_handle64 *ph) __QAIC_REMOTE_ATTRIBUTE; + +/* invokes the remote handle + * see retrive macro's on dwScalars format + * pra, contains the arguments in the following order, inbufs, outbufs, inhandles, outhandles. + * implementors should ignore and pass values asis that the transport doesn't understand. + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_invoke)(remote_handle h, uint32_t dwScalars, remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_invoke)(remote_handle64 h, uint32_t dwScalars, remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; + +/* closes the remote handle + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_close)(remote_handle h) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_close)(remote_handle64 h) __QAIC_REMOTE_ATTRIBUTE; + +/* remote handle control interface + */ +/* request ID for fastrpc latency control */ +#define DSPRPC_CONTROL_LATENCY (1) +struct remote_rpc_control_latency { + uint32_t enable; // enable auto control of rpc latency + uint32_t latency; // latency: reserved +}; + +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_control)(uint32_t req, void* data, uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_control)(remote_handle64 h, uint32_t req, void* data, uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; + +/* remote session control interface + */ +/* request ID for setting DSP user thread params */ +#define FASTRPC_THREAD_PARAMS (1) +struct remote_rpc_thread_params { + int domain; // Remote subsystem domain ID, pass -1 to set params for all domains + int prio; // user thread priority (1 to 255), pass -1 to use default + int stack_size; // user thread stack size, pass -1 to use default +}; + +/* request ID for fastrpc unsigned module */ +#define DSPRPC_CONTROL_UNSIGNED_MODULE (2) +struct remote_rpc_control_unsigned_module { + int domain; // Remote subsystem domain ID, -1 to set params for all domains + int enable; // enable unsigned module loading +}; + +/* Set remote session parameters + * + * @param req, request ID + * @param data, address of structure with parameters + * @param datalen, length of data + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_session_control)(uint32_t req, void *data, uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; + +/* map memory to the remote domain + * + * @param fd, fd assosciated with this memory + * @param flags, flags to be used for the mapping + * @param vaddrin, input address + * @param size, size of buffer + * @param vaddrout, output address + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_mmap)(int fd, uint32_t flags, uint32_t vaddrin, int size, uint32_t* vaddrout) __QAIC_REMOTE_ATTRIBUTE; + +/* unmap memory from the remote domain + * + * @param vaddrout, remote address mapped + * @param size, size to unmap. Unmapping a range partially may not be supported. + * @retval, 0 on success, may fail if memory is still mapped + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_munmap)(uint32_t vaddrout, int size) __QAIC_REMOTE_ATTRIBUTE; + +/* + * Attribute to map a buffer as dma non-coherent + * Driver perform cache maintenance. + */ +#define FASTRPC_ATTR_NON_COHERENT (2) + +/* + * Attribute to map a buffer as dma coherent + * Driver skips cache maintenenace + * It will be ignored if a device is marked as dma-coherent in device tree. + */ +#define FASTRPC_ATTR_COHERENT (4) + +/* Attribute to keep the buffer persistant + * until unmap is called explicitly + */ +#define FASTRPC_ATTR_KEEP_MAP (8) + +/* + * Attribute for secure buffers to skip + * smmu mapping in fastrpc driver + */ +#define FASTRPC_ATTR_NOMAP (16) + +/* Register a file descriptor for a buffer. This is only valid on + * android with ION allocated memory. Users of fastrpc should register + * a buffer allocated with ION to enable sharing that buffer to the + * dsp via the smmu. Some versions of libadsprpc.so lack this + * function, so users should set this symbol as weak. + * + * #pragma weak remote_register_buf + * #pragma weak remote_register_buf_attr + * + * @param buf, virtual address of the buffer + * @param size, size of the buffer + * @fd, the file descriptor, callers can use -1 to deregister. + * @attr, map buffer as coherent or non-coherent + */ +__QAIC_REMOTE_EXPORT void __QAIC_REMOTE(remote_register_buf)(void* buf, int size, int fd) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT void __QAIC_REMOTE(remote_register_buf_attr)(void* buf, int size, int fd, int attr) __QAIC_REMOTE_ATTRIBUTE; + +/* Register a dma handle with fastrpc. This is only valid on + * android with ION allocated memory. Users of fastrpc should register + * a file descriptor allocated with ION to enable sharing that memory to the + * dsp via the smmu. Some versions of libadsprpc.so lack this + * function, so users should set this symbol as weak. + * + * #pragma weak remote_register_dma_handle + * #pragma weak remote_register_dma_handle_attr + * + * @fd, the file descriptor, callers can use -1 to deregister. + * @param len, size of the buffer + * @attr, map buffer as coherent or non-coherent or no-map + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_register_dma_handle)(int fd, uint32_t len) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_register_dma_handle_attr)(int fd, uint32_t len, uint32_t attr) __QAIC_REMOTE_ATTRIBUTE; + +/* + * This is the default mode for the driver. While the driver is in parallel + * mode it will try to invalidate output buffers after it transfers control + * to the dsp. This allows the invalidate operations to overlap with the + * dsp processing the call. This mode should be used when output buffers + * are only read on the application processor and only written on the aDSP. + */ +#define REMOTE_MODE_PARALLEL 0 + +/* + * When operating in SERIAL mode the driver will invalidate output buffers + * before calling into the dsp. This mode should be used when output + * buffers have been written to somewhere besides the aDSP. + */ +#define REMOTE_MODE_SERIAL 1 + +/* + * Internal transport prefix + */ +#define ITRANSPORT_PREFIX "'\":;./\\" + +/* + * Set the mode of operation. + * + * Some versions of libadsprpc.so lack this function, so users should set + * this symbol as weak. + * + * #pragma weak remote_set_mode + * + * @param mode, the mode + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_set_mode)(uint32_t mode) __QAIC_REMOTE_ATTRIBUTE; + +/* Register a file descriptor. This can be used when users do not have + * a mapping to pass to the RPC layer. The generated address is a mapping + * with PROT_NONE, any access to this memory will fail, so it should only + * be used as an ID to identify this file descriptor to the RPC layer. + * + * To deregister use remote_register_buf(addr, size, -1). + * + * #pragma weak remote_register_fd + * + * @param fd, the file descriptor. + * @param size, size to of the buffer + * @retval, (void*)-1 on failure, address on success. + * + */ +__QAIC_REMOTE_EXPORT void *__QAIC_REMOTE(remote_register_fd)(int fd, int size) __QAIC_REMOTE_ATTRIBUTE; + +#ifdef __cplusplus +} +#endif + +#endif // REMOTE_H diff --git a/inc/remote64.h b/inc/remote64.h new file mode 100644 index 0000000..341b2ca --- /dev/null +++ b/inc/remote64.h @@ -0,0 +1,96 @@ +/** + * 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 REMOTE64_H +#define REMOTE64_H + +#include "remote.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint64_t pv; + int64_t nLen; +} remote_buf64; + +typedef struct { + int32_t fd; + uint32_t offset; + uint32_t len; +} remote_dma_handle64; + +typedef union { + remote_buf64 buf; + remote_handle h; + remote_handle64 h64; //! used by multi domain modules + remote_dma_handle64 dma; +} remote_arg64; + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_REMOTE_EXPORT +#ifdef _WIN32 +#define __QAIC_REMOTE_EXPORT __declspec(dllexport) +#else //_WIN32 +#define __QAIC_REMOTE_EXPORT +#endif //_WIN32 +#endif //__QAIC_REMOTE_EXPORT + +#ifndef __QAIC_REMOTE_ATTRIBUTE +#define __QAIC_REMOTE_ATTRIBUTE +#endif + +/* map memory to the remote domain + * + * @param fd, fd associated with this memory + * @param flags, flags to be used for the mapping + * @param vaddrin, input address + * @param size, size of buffer + * @param vaddrout, output address + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_mmap64)(int fd, uint32_t flags, uint64_t vaddrin, int64_t size, uint64_t *vaddrout) __QAIC_REMOTE_ATTRIBUTE; + +/* unmap memory from the remote domain + * + * @param vaddrout, remote address mapped + * @param size, size to unmap. Unmapping a range partially may not be supported. + * @retval, 0 on success, may fail if memory is still mapped + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_munmap64)(uint64_t vaddrout, int64_t size) __QAIC_REMOTE_ATTRIBUTE; + +#ifdef __cplusplus +} +#endif + +#endif // REMOTE64_H diff --git a/inc/remotectl.h b/inc/remotectl.h new file mode 100644 index 0000000..3302a46 --- /dev/null +++ b/inc/remotectl.h @@ -0,0 +1,76 @@ +/** + * 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_H +#define _REMOTECTL_H +#include "AEEStdDef.h" +#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 +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +#define _const_remotectl_handle 0 +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_open)(const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_close)(int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_grow_heap)(uint32 phyAddr, uint32 nSize) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_set_param)(int reqID, const uint32* params, int paramsLen) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_REMOTECTL_H diff --git a/inc/rpcmem.h b/inc/rpcmem.h new file mode 100644 index 0000000..28f3a77 --- /dev/null +++ b/inc/rpcmem.h @@ -0,0 +1,140 @@ +/** + * 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 RPCMEM_H +#define RPCMEM_H + +#include "AEEStdDef.h" + +/** + * RPCMEM_DEFAULT_HEAP + * Dynamicaly select the heap to use. This should be ok for most usecases. + */ +#define RPCMEM_DEFAULT_HEAP -1 + + +/** + * RPCMEM_DEFAULT_FLAGS should allocate memory with the same properties + * as the ION_FLAG_CACHED flag + */ +#ifdef ION_FLAG_CACHED +#define RPCMEM_DEFAULT_FLAGS ION_FLAG_CACHED +#else +#define RPCMEM_DEFAULT_FLAGS 1 +#endif + +/** + * RPCMEM_FLAG_UNCACHED + * ION_FLAG_CACHED should be defined as 1 + */ +#define RPCMEM_FLAG_UNCACHED 0 +#define RPCMEM_FLAG_CACHED RPCMEM_DEFAULT_FLAGS + +/** + * examples: + * + * heap 22, uncached, 1kb + * rpcmem_alloc(22, 0, 1024); + * rpcmem_alloc(22, RPCMEM_FLAG_UNCACHED, 1024); + * + * heap 21, cached, 2kb + * rpcmem_alloc(21, RPCMEM_FLAG_CACHED, 2048); + * #include <ion.h> + * rpcmem_alloc(21, ION_FLAG_CACHED, 2048); + * + * just give me the defaults, 2kb + * rpcmem_alloc(RPCMEM_DEFAULT_HEAP, RPCMEM_DEFAULT_FLAGS, 2048); + * rpcmem_alloc_def(2048); + * + * give me the default flags, but from heap 18, 4kb + * rpcmem_alloc(18, RPCMEM_DEFAULT_FLAGS, 4096); + * + */ +#define ION_SECURE_FLAGS ((1 << 31) | (1 << 19)) +#ifdef __cplusplus +extern "C" { +#endif + +/** + * call once to initialize the library + * Note: should not call this if rpcmem is linked from libadsprpc.so + * /libcdsprpc.so/libmdsprpc.so/libsdsprpc.so + */ +void rpcmem_init(void); +/** + * call once for cleanup + * Note: should not call this if rpcmem is linked from libadsprpc.so + * /libcdsprpc.so/libmdsprpc.so/libsdsprpc.so + */ +void rpcmem_deinit(void); + +/** + * Allocate via ION a buffer of size + * @heapid, the heap id to use + * @flags, ion flags to use to when allocating + * @size, the buffer size to allocate + * @retval, 0 on failure, pointer to buffer on success + * + * For example: + * buf = rpcmem_alloc(RPCMEM_DEFAULT_HEAP, RPCMEM_DEFAULT_FLAGS, size); + */ + +void* rpcmem_alloc(int heapid, uint32 flags, int size); + +/** + * allocate with default settings + */ + #if !defined(WINNT) && !defined (_WIN32_WINNT) +__attribute__((unused)) +#endif +static __inline void* rpcmem_alloc_def(int size) { + return rpcmem_alloc(RPCMEM_DEFAULT_HEAP, RPCMEM_DEFAULT_FLAGS, size); +} + +/** + * free buffer, ignores invalid buffers + */ +void rpcmem_free(void* po); + +/** + * returns associated fd + */ +int rpcmem_to_fd(void* po); + +#ifdef __cplusplus +} +#endif + +#define RPCMEM_HEAP_DEFAULT 0x80000000 +#define RPCMEM_HEAP_NOREG 0x40000000 +#define RPCMEM_HEAP_UNCACHED 0x20000000 +#define RPCMEM_HEAP_NOVA 0x10000000 +#define RPCMEM_HEAP_NONCOHERENT 0x08000000 + +#endif //RPCMEM_H diff --git a/inc/sbuf.h b/inc/sbuf.h new file mode 100644 index 0000000..96775c8 --- /dev/null +++ b/inc/sbuf.h @@ -0,0 +1,175 @@ +/** + * 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 SBUF_H +#define SBUF_H + +#include <string.h> +#include <stdint.h> +#include "AEEstd.h" + +/** + * lightweight serialize/deserialize buffer. + + For example + + struct sbuf; + //initialize empty buffer; + sbuf_init(&sbuf, 0, 0, 0); + + //fill it with data + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr1, 10); + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr2, 20); + + //allocate the memory needed + mem = malloc(sbuf_needed(&sbuf)); + + //initialize with the data + sbuf_init(&sbuf, 0, mem, sbuf_needed(&sbuf)); + + //fill it with data, since it has memory, it will actually copy + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr1, 10); + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr2, 20); + + See sbuf_q.c for more examples + */ + + +struct sbuf { + uintptr_t buf; //! start of valid memory + uintptr_t bufEnd; //! end of valid memory + uintptr_t bufStart; //! start with optinal offset from valid mem + uintptr_t bufCur; //! current position, could be outside of valid range +}; + +/** + * @param buf, the buffer structure instance + * @param offset, this value indicates how far ahead the data buffer is + * start = data - offset + * @param data, the valid memory + * @param dataLen, the length ov valid memory + */ +static __inline void sbuf_init(struct sbuf* buf, int offset, void* data, int dataLen) { + buf->buf = (uintptr_t)data; + buf->bufStart = buf->bufCur = (uintptr_t)data - offset; + buf->bufEnd = (uintptr_t)data + dataLen; +} + +//! move the current pointer by len +static __inline void sbuf_advance(struct sbuf* buf, int len) { + buf->bufCur += len; +} + +/** + * @retval, the amount of memory needed for everything from the start (with the offset) + * to the current position of the buffer + */ +static __inline int sbuf_needed(struct sbuf* buf) { + return buf->bufCur - buf->bufStart; +} +/** + * @retval, the space left in the buffer. A negative value indicates overflow. + * A positive value includes the offset. + */ +static __inline int sbuf_left(struct sbuf* buf) { + return buf->bufEnd - buf->bufCur; +} + +//! @retval the current head pointer +static __inline void* sbuf_head(struct sbuf* buf) { + return (void*)buf->bufCur; +} + +//! @retval true if the current pointer is valid +static __inline int sbuf_valid(struct sbuf* buf) { + return buf->bufCur >= buf->buf && buf->bufCur < buf->bufEnd; +} + +//! advance the head pointer so the "needed" is aligned to the align value +#define _SBUF_ALIGN(x, y) (((x) + ((y)-1)) & ~((y)-1)) +static __inline void sbuf_align(struct sbuf* buf, uint32_t align) { + sbuf_advance(buf, _SBUF_ALIGN(sbuf_needed(buf), align) - sbuf_needed(buf)); +} + +/** + * Write to the buffer. + * @param src, the memory to read from. Will write srcLen bytes to buf from src + * from the buf's current position. Only the valid portion of data will + * be written. + * @param srcLen, the length of src. The buffer will be advanced by srcLen. + */ +static __inline void sbuf_write(struct sbuf* buf, void *psrc, int srcLen) { + uintptr_t src = (uintptr_t)psrc; + if(buf->bufCur + srcLen > buf->buf) { + int writeLen; + if(buf->bufCur < buf->buf) { + int len = buf->buf - buf->bufCur; + srcLen -= len; + src += len; + sbuf_advance(buf, len); + } + writeLen = STD_MIN(srcLen, sbuf_left(buf)); + if(writeLen > 0) { + std_memsmove((void*)buf->bufCur, buf->bufEnd - buf->bufCur, (void*)src, writeLen); + } + } + sbuf_advance(buf, srcLen); +} + +/** + * Read from the buffer into dst. + * @param dst, the data to write to. Will write dstLen to dst from buf + * from the current position of buf. Only valid memory + * will be written to dst. Invalid overlapping memory will + * remain untouched. + * @param dstLen, the length of dst. buf will be advanced by dstLen + */ +static __inline void sbuf_read(struct sbuf* buf, void *pdst, int dstLen) { + uintptr_t dst = (uintptr_t)pdst; + if(buf->bufCur + dstLen > buf->buf) { + int readLen; + if(buf->bufCur < buf->buf) { + int len = buf->buf - buf->bufCur; + dstLen -= len; + dst += len; + sbuf_advance(buf, len); + } + readLen = STD_MIN(dstLen, sbuf_left(buf)); + if(readLen > 0) { + std_memsmove((void*)dst, dstLen, (void*)buf->bufCur, readLen); + } + } + sbuf_advance(buf, dstLen); +} + +#endif diff --git a/inc/sbuf_parser.h b/inc/sbuf_parser.h new file mode 100644 index 0000000..b4e0b28 --- /dev/null +++ b/inc/sbuf_parser.h @@ -0,0 +1,266 @@ +/** + * 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 SBUF_PARSER_H +#define SBUF_PARSER_H + +#include "sbuf.h" + +/** + * Greedy Recursive Descent Parser in C + * + * Stop using strstr or regular expressions. This simple Recursive Descent Parser can be + * used to handle complex grammars. + * + * For example: + * parsing a query string form a uri + * input: "file:///foo/bar_far.so.1?_blah1&_bar=barval5&_barfar" + * expected output: + * parsed query: _blah1 = + * parsed query: _bar = barval5 + * parsed query: _barfar = + * + * static int qmark(struct sbuf *buf) { + * return sbuf_char(buf, '?'); + * } + * static int notandoreq(struct sbuf *buf) { + * return sbuf_notchars(buf, "&="); + * } + * static int notand(struct sbuf *buf) { + * return sbuf_notchar(buf, '&'); + * } + * + * const char *name; + * int nameLen; + * const char *value; + * int valueLen; + * const char *data = "file:///foo/bar_far.so.1?_blah1&_bar=barval5&_barfar"; + * + * //initialize + * sbuf_parser_init(&buf, data, strlen(data)); + * + * //parse until question mark + * assert(sbuf_until(&buf, sbuf_any, qmark)); + * + * //parse each query + * while(!sbuf_end(&buf)) { + * //record where the name starts + * name = sbuf_cur(&buf); + * + * //name is valid until '=' or '&' + * assert(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 '&' + * assert(sbuf_many1(&buf, notand)); + * valueLen = sbuf_cur(&buf) - value; + * } + * //expect '&' or end + * sbuf_char(&buf, '&'); + * printf("parsed query: %.*s = %.*s\n", nameLen, name, valueLen, value); + * } + * + */ + +//! init +static __inline void sbuf_parser_init(struct sbuf* buf, const char *data, int dataLen) { + sbuf_init(buf, 0, (void*)data, dataLen); +} + +//! current postiion +static __inline char *sbuf_cur(struct sbuf* buf) { + return (char*)sbuf_head(buf); +} + +//! look at the next character if the buffer is still valid +static __inline int sbuf_peek(struct sbuf* buf, char* c) { + if(!sbuf_valid(buf)) { + return 0; + } + *c = *sbuf_cur(buf); + return 1; +} + +//! returns true if the buffer is ended +static __inline int sbuf_end(struct sbuf* buf) { + return sbuf_left(buf) == 0; +} + +//! consume 1 char if its in string chars +static __inline int sbuf_chars(struct sbuf *buf, const char *chars) { + int i = 0; + char c; + if(!sbuf_peek(buf, &c)) { + return 0; + } + for(i = 0; chars[i] != 0; ++i) { + if(c == chars[i]) { + sbuf_advance(buf, 1); + return 1; + } + } + return 0; +} + +//! consume 1 char only if its not in string chars +static __inline int sbuf_notchars(struct sbuf *buf, const char *chars) { + int i = 0; + char c; + if(!sbuf_peek(buf, &c)) { + return 0; + } + for(i = 0; chars[i] != 0; ++i) { + if(c == chars[i]) { + return 0; + } + } + sbuf_advance(buf, 1); + return 1; +} + +//! consume only char t +static __inline int sbuf_char(struct sbuf *buf, const char t) { + char str[2] = {t, 0}; + return sbuf_chars(buf, str); +} + +//! consume any char except for t +static __inline int sbuf_notchar(struct sbuf *buf, const char t) { + char str[2] = {t, 0}; + return sbuf_notchars(buf, str); +} + +/** + * consume any char + */ +static __inline int sbuf_any(struct sbuf* buf) { + return sbuf_notchars(buf, ""); +} + + +/** + * range is pairs of characters + * + * pairs are inclusive, start must be less then or equal then the end + * + * for example: AZaz09--.. + * matches uppercase and lowercase letters, numbers, dashes and dots + * + */ +static __inline int sbuf_range(struct sbuf *buf, const char *chars) { + int i, j; + char c; + if(!sbuf_peek(buf, &c)) { + return 0; + } + for(i = 0, j = 1; chars[i] != 0 && chars[j] != 0; i+=2,j+=2) { + if(c >= chars[i] && c <= chars[j]) { + sbuf_advance(buf, 1); + return 1; + } + } + return 0; +} + + +/** + * greedly consume and match the entire string + * empty string always succeeds without consuming any data + */ +static __inline int sbuf_string(struct sbuf *buf, const char *str) { + int i = 0; + for(i = 0; str[i] != 0; ++i) { + if(!sbuf_char(buf, str[i])) { + return 0; + } + } + return 1; +} + +/** + * consumes until fails + */ +static __inline int sbuf_many(struct sbuf *buf, + int(*consume)(struct sbuf *buf)) +{ + if(!sbuf_valid(buf)) { + return 0; + } + while(consume(buf)) {;} + return 1; +} +/** + * consumes until fails, must consume at least 1 + */ +static __inline int sbuf_many1(struct sbuf *buf, + int(*consume)(struct sbuf *buf)) +{ + if(!consume(buf)) { + return 0; + } + sbuf_many(buf, consume); + return 1; +} +/** + * runs 'consume' until 'stop' succeeds + * 'stop' must fail in such a way that it doesn't consume any data + */ +static __inline int sbuf_until(struct sbuf *buf, + int(*consume)(struct sbuf *buf), + int(*stop)(struct sbuf *buf)) +{ + while(!stop(buf)) { + if(!consume(buf)) { + return 0; + } + } + return 1; +} + +/** + * allows for backtracking, + * @param parser, runs parser and only consume if it succeeds + */ +static __inline int sbuf_try(struct sbuf *buf, int(*parser)(struct sbuf *buf)) +{ + struct sbuf tryp; + sbuf_parser_init(&tryp, sbuf_cur(buf), sbuf_left(buf)); + if(parser(&tryp)) { + sbuf_advance(buf, sbuf_cur(&tryp) - sbuf_cur(buf)); + return 1; + } + return 0; +} +#endif // SBUF_PARSER_H diff --git a/inc/shared.h b/inc/shared.h new file mode 100644 index 0000000..14c4f19 --- /dev/null +++ b/inc/shared.h @@ -0,0 +1,81 @@ +/** + * 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 SHARED_H +#define SHARED_H + +#if defined(__NIX) +// TODO these sections not supported? +//static __so_func *__autostart[] __attribute__((section (".CRT$XIU"))) = { (__so_func*)__so_ctor }; +//static __so_func *__autoexit[] __attribute__((section (".CRT$XPU"))) = { (__so_func*)__so_dtor }; + +#define SHARED_OBJECT_API_ENTRY(ctor, dtor) + +#elif defined(_WIN32) +#include <windows.h> + +typedef int __so_cb(void); +static __so_cb *__so_get_ctor(); +static __so_cb *__so_get_dtor(); + +typedef void __so_func(void); +static void __so_ctor() { + (void)(__so_get_ctor())(); +} + +static void __so_dtor() { + (void)(__so_get_dtor())(); +} + +#pragma data_seg(".CRT$XIU") + static __so_func *__autostart[] = { (__so_func*)__so_ctor }; +#pragma data_seg(".CRT$XPU") + static __so_func *__autoexit[] = { (__so_func*)__so_dtor }; +#pragma data_seg() + +#define SHARED_OBJECT_API_ENTRY(ctor, dtor)\ + static __so_cb *__so_get_ctor() { return (__so_cb*)ctor; }\ + static __so_cb *__so_get_dtor() { return (__so_cb*)dtor; } + +#else //better be gcc + +#define SHARED_OBJECT_API_ENTRY(ctor, dtor)\ +__attribute__((constructor)) \ +static void __ctor__##ctor(void) {\ + (void)ctor();\ +}\ +\ +__attribute__((destructor))\ +static void __dtor__##dtor(void) {\ + (void)dtor();\ +} + +#endif //ifdef _WIN32 + +#endif // SHARED_H diff --git a/inc/uthash.h b/inc/uthash.h new file mode 100644 index 0000000..dfee1c8 --- /dev/null +++ b/inc/uthash.h @@ -0,0 +1,920 @@ +/* +Copyright (c) 2003-2011, Troy D. Hanson http://uthash.sourceforge.net +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE 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 UTHASH_H +#define UTHASH_H + +#include <string.h> /* memcmp,strlen */ +#include <stddef.h> /* ptrdiff_t */ +#include <stdlib.h> /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#else +#include <inttypes.h> /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.4 + +#ifndef UTHASH_MALLOC +#define UTHASH_MALLOC malloc +#endif + +#ifndef UTHASH_FREE +#define UTHASH_FREE free +#endif + +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_malloc(sz) UTHASH_MALLOC(sz) /* malloc fcn */ +#define uthash_free(ptr,sz) UTHASH_FREE(ptr) /* free fcn */ + +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0); + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0); + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((char*)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + +/* use this function to delete an item from a table only if its in that table */ +#define HASH_DELETE_IF(hh,group,ptr) \ +do {\ + if(ptr && group && ptr->hh.tbl) { \ + HASH_DELETE(hh,group,ptr); \ + ptr->hh.tbl = 0;\ + } \ +} while(0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include <unistd.h> to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + char *_hj_key=(char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + char *_sfh_key=(char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + uint32_t _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + const uint8_t *_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + uint32_t _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if (out->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/inc/verify.h b/inc/verify.h new file mode 100644 index 0000000..b5e5c21 --- /dev/null +++ b/inc/verify.h @@ -0,0 +1,150 @@ +/** + * 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_H +#define VERIFY_H + +#include "AEEstd.h" + +//#define VERIFY_PRINT_ERROR +//#define VERIFY_PRINT_INFO + + +#ifndef _WIN32 +#define C_ASSERT(test) \ + switch(0) {\ + case 0:\ + case test:;\ + } +#endif // _WIN32 + +#ifndef __V_STR__ + #define __V_STR__(x) #x ":" +#endif //__STR__ +#ifndef __V_TOSTR__ + #define __V_TOSTR__(x) __V_STR__(x) +#endif // __TOSTR__ +#ifndef __V_FILE_LINE__ + #define __V_FILE_LINE__ __FILE__ ":" __V_TOSTR__(__LINE__) +#endif /*__FILE_LINE__*/ + + +#ifdef __ANDROID__ +/*android */ +#if (defined VERIFY_PRINT_INFO) || (defined VERIFY_PRINT_ERROR) +#include <android/log.h> +#endif + +extern const char* __progname; +#ifdef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format, ...) __android_log_print(ANDROID_LOG_DEBUG , __progname, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +#ifdef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) __android_log_print(ANDROID_LOG_ERROR , __progname, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +/* end android */ +#elif (defined __hexagon__) || (defined __qdsp6__) +/* q6 */ + +#ifdef VERIFY_PRINT_INFO + #define FARF_VERIFY_LOW 1 + #define FARF_VERIFY_LOW_LEVEL HAP_LEVEL_LOW + #define VERIFY_IPRINTF(args...) FARF(VERIFY_LOW, args) +#endif + +#ifdef VERIFY_PRINT_ERROR + #define FARF_VERIFY_ERROR 1 + #define FARF_VERIFY_ERROR_LEVEL HAP_LEVEL_ERROR + #define VERIFY_EPRINTF(args...) FARF(VERIFY_ERROR, args) +#endif + +#if (defined VERIFY_PRINT_INFO) || (defined VERIFY_PRINT_ERROR) + #include "HAP_farf.h" +#endif + +/* end q6 */ +#else +/* generic */ + +#if (defined VERIFY_PRINT_INFO) || (defined VERIFY_PRINT_ERROR) +#include <stdio.h> +#endif + +#ifdef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format, ...) printf(__V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +#ifdef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) printf(__V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +/* end generic */ +#endif + +#ifndef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format, ...) (void)0 +#endif + +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) (void)0 +#endif + +#ifndef VERIFY + #define VERIFY(val) \ + do {\ + VERIFY_IPRINTF(":info: calling: " #val "\n");\ + if(0 == (val)) {\ + nErr = nErr == 0 ? -1 : nErr;\ + VERIFY_EPRINTF(":error: %d: " #val "\n", nErr);\ + goto bail;\ + } else {\ + VERIFY_IPRINTF(":info: passed: " #val "\n");\ + }\ + } while(0) +#endif //VERIFY + +#ifndef VERIFYC + #define VERIFYC(val,err_code) \ + do {\ + VERIFY_IPRINTF(":info: calling: " #val "\n");\ + if(0 == (val)) {\ + nErr = err_code;\ + VERIFY_EPRINTF(":Error: %x: " #val "\n", nErr);\ + goto bail;\ + } else {\ + VERIFY_IPRINTF(":info: passed: " #val "\n");\ + }\ + } while(0) +#endif //VERIFYC + + +#endif //VERIFY_H + diff --git a/inc/verify_android.h b/inc/verify_android.h new file mode 100644 index 0000000..43bc3a2 --- /dev/null +++ b/inc/verify_android.h @@ -0,0 +1,47 @@ +/** + * 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_ANDROID +#define VERIFY_ANDROID + +#ifdef __ANDROID__ + +#include <android/log.h> + +#ifdef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format) __android_log_print(ANDROID_LOG_DEBUG , "adsprpc", format) +#endif + +#ifdef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) __android_log_print(ANDROID_LOG_ERROR , "adsprpc", format, ##__VA_ARGS__) +#endif + +#endif //ANDROID + +#endif //VERIFY_ANDROID diff --git a/inc/version.h b/inc/version.h new file mode 100644 index 0000000..c75bc86 --- /dev/null +++ b/inc/version.h @@ -0,0 +1,119 @@ +#ifndef VERSION_H +#define VERSION_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. + */ + +#if !defined(VERSION_CL) +#define VERSION_CL "?" +#endif + +#if !defined(VERSION_PROD) +#define VERSION_PROD "unknown" +#endif + +#if !defined(VERSION_BRANCH) +#define VERSION_BRANCH "?" +#endif + +#if !defined(VERSION_NUM) +#define VERSION_NUM "?.?.?.?" +#endif + +#define VERSION_STRING \ + VERSION_PROD " " \ + VERSION_NUM " " \ + "(br=" VERSION_BRANCH "; cl=" VERSION_CL ")" + +/* +======================================================================= +MACROS DOCUMENTATION +======================================================================= + +VERSION_MAJOR + +Description: + Defines the major release number of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_MINOR + +Description: + Defines the minor release number of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_MAINT + +Description: + Defines the maintenance release of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_BUILD + +Description: + Defines the build ID of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_STRING + +Description: + Defines the version string that specifies the version number. + +Definition: + + #define VERSION_STRING "a.b.c.d (name=value;name=value;...)" + where a=major release number + b=minor release number + c=maintenance release number + d=build number + + name=value pair provides additional information about the build. + Example: + patch/feature=comma separated list of features/patches that have been installed. + br=p4 branch that was used for the build + cl=p4 change list number + machine=hostname of the machine that was used for the build. + +Comments: + +======================================================================= +*/ + +#endif // VERSION_H 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: *; +}; |