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