• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *    * Redistributions of source code must retain the above copyright
8  *      notice, this list of conditions and the following disclaimer.
9  *    * Redistributions in binary form must reproduce the above
10  *      copyright notice, this list of conditions and the following
11  *      disclaimer in the documentation and/or other materials provided
12  *      with the distribution.
13  *    * Neither the name of The Linux Foundation nor the names of its
14  *      contributors may be used to endorse or promote products derived
15  *      from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef SBUF_H
31 #define SBUF_H
32 
33 #include <string.h>
34 #include <stdint.h>
35 #include "AEEstd.h"
36 
37 /**
38  * lightweight serialize/deserialize buffer.
39 
40    For example
41 
42    struct sbuf;
43    //initialize empty buffer;
44    sbuf_init(&sbuf, 0, 0, 0);
45 
46    //fill it with data
47    sbuf_align(&sbuf, 8);
48    sbuf_write(&sbuf, ptr1, 10);
49    sbuf_align(&sbuf, 8);
50    sbuf_write(&sbuf, ptr2, 20);
51 
52    //allocate the memory needed
53    mem = malloc(sbuf_needed(&sbuf));
54 
55    //initialize with the data
56    sbuf_init(&sbuf, 0, mem, sbuf_needed(&sbuf));
57 
58    //fill it with data, since it has memory, it will actually copy
59    sbuf_align(&sbuf, 8);
60    sbuf_write(&sbuf, ptr1, 10);
61    sbuf_align(&sbuf, 8);
62    sbuf_write(&sbuf, ptr2, 20);
63 
64    See sbuf_q.c for more examples
65  */
66 
67 
68 struct sbuf {
69    uintptr_t buf;      //! start of valid memory
70    uintptr_t bufEnd;   //! end of valid memory
71    uintptr_t bufStart; //! start with optinal offset from valid mem
72    uintptr_t bufCur;   //! current position, could be outside of valid range
73 };
74 
75 /**
76  * @param buf, the buffer structure instance
77  * @param offset, this value indicates how far ahead the data buffer is
78  *                start = data - offset
79  * @param data, the valid memory
80  * @param dataLen, the length ov valid memory
81  */
sbuf_init(struct sbuf * buf,int offset,void * data,int dataLen)82 static __inline void sbuf_init(struct sbuf* buf, int offset, void* data, int dataLen) {
83    buf->buf = (uintptr_t)data;
84    buf->bufStart = buf->bufCur = (uintptr_t)data - offset;
85    buf->bufEnd = (uintptr_t)data + dataLen;
86 }
87 
88 //! move the current pointer by len
sbuf_advance(struct sbuf * buf,int len)89 static __inline void sbuf_advance(struct sbuf* buf, int len) {
90    buf->bufCur += len;
91 }
92 
93 /**
94  * @retval, the amount of memory needed for everything from the start (with the offset)
95  * to the current position of the buffer
96  */
sbuf_needed(struct sbuf * buf)97 static __inline int sbuf_needed(struct sbuf* buf) {
98    return buf->bufCur - buf->bufStart;
99 }
100 /**
101  * @retval, the space left in the buffer. A negative value indicates overflow.
102  *          A positive value includes the offset.
103  */
sbuf_left(struct sbuf * buf)104 static __inline int sbuf_left(struct sbuf* buf) {
105    return buf->bufEnd - buf->bufCur;
106 }
107 
108 //! @retval the current head pointer
sbuf_head(struct sbuf * buf)109 static __inline void* sbuf_head(struct sbuf* buf) {
110    return (void*)buf->bufCur;
111 }
112 
113 //! @retval true if the current pointer is valid
sbuf_valid(struct sbuf * buf)114 static __inline int sbuf_valid(struct sbuf* buf) {
115    return buf->bufCur >= buf->buf && buf->bufCur < buf->bufEnd;
116 }
117 
118 //! advance the head pointer so the "needed" is aligned to the align value
119 #define _SBUF_ALIGN(x, y) (((x) + ((y)-1)) & ~((y)-1))
sbuf_align(struct sbuf * buf,uint32_t align)120 static __inline void sbuf_align(struct sbuf* buf, uint32_t align) {
121    sbuf_advance(buf, _SBUF_ALIGN(sbuf_needed(buf), align) - sbuf_needed(buf));
122 }
123 
124 /**
125  * Write to the buffer.
126  * @param src, the memory to read from.  Will write srcLen bytes to buf from src
127  *             from the buf's current position.  Only the valid portion of data will
128  *             be written.
129  * @param srcLen, the length of src.  The buffer will be advanced by srcLen.
130  */
sbuf_write(struct sbuf * buf,void * psrc,int srcLen)131 static __inline void sbuf_write(struct sbuf* buf, void *psrc, int srcLen) {
132    uintptr_t src = (uintptr_t)psrc;
133    if(buf->bufCur + srcLen > buf->buf) {
134       int writeLen;
135       if(buf->bufCur < buf->buf) {
136          int len = buf->buf - buf->bufCur;
137          srcLen -= len;
138          src += len;
139          sbuf_advance(buf, len);
140       }
141       writeLen = STD_MIN(srcLen, sbuf_left(buf));
142       if(writeLen > 0) {
143          std_memsmove((void*)buf->bufCur, buf->bufEnd - buf->bufCur, (void*)src, writeLen);
144       }
145    }
146    sbuf_advance(buf, srcLen);
147 }
148 
149 /**
150  * Read from the buffer into dst.
151  * @param dst, the data to write to. Will write dstLen to dst from buf
152  *             from the current position of buf.  Only valid memory
153  *             will be written to dst.  Invalid overlapping memory will
154  *             remain untouched.
155  * @param dstLen, the length of dst.  buf will be advanced by dstLen
156  */
sbuf_read(struct sbuf * buf,void * pdst,int dstLen)157 static __inline void sbuf_read(struct sbuf* buf, void *pdst, int dstLen) {
158    uintptr_t dst = (uintptr_t)pdst;
159    if(buf->bufCur + dstLen > buf->buf) {
160       int readLen;
161       if(buf->bufCur < buf->buf) {
162          int len = buf->buf - buf->bufCur;
163          dstLen -= len;
164          dst += len;
165          sbuf_advance(buf, len);
166       }
167       readLen = STD_MIN(dstLen, sbuf_left(buf));
168       if(readLen > 0) {
169          std_memsmove((void*)dst, dstLen, (void*)buf->bufCur, readLen);
170       }
171    }
172    sbuf_advance(buf, dstLen);
173 }
174 
175 #endif
176