xref: /aosp_15_r20/external/virglrenderer/src/iov.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker  * this code is taken from Michael - the qemu code is GPLv2 so I don't want
3*bbecb9d1SAndroid Build Coastguard Worker  * to reuse it.
4*bbecb9d1SAndroid Build Coastguard Worker  * I've adapted it to handle offsets and callback
5*bbecb9d1SAndroid Build Coastguard Worker  */
6*bbecb9d1SAndroid Build Coastguard Worker 
7*bbecb9d1SAndroid Build Coastguard Worker //
8*bbecb9d1SAndroid Build Coastguard Worker // iovec.c
9*bbecb9d1SAndroid Build Coastguard Worker //
10*bbecb9d1SAndroid Build Coastguard Worker // Scatter/gather utility routines
11*bbecb9d1SAndroid Build Coastguard Worker //
12*bbecb9d1SAndroid Build Coastguard Worker // Copyright (C) 2002 Michael Ringgaard. All rights reserved.
13*bbecb9d1SAndroid Build Coastguard Worker //
14*bbecb9d1SAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
15*bbecb9d1SAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions
16*bbecb9d1SAndroid Build Coastguard Worker // are met:
17*bbecb9d1SAndroid Build Coastguard Worker //
18*bbecb9d1SAndroid Build Coastguard Worker // 1. Redistributions of source code must retain the above copyright
19*bbecb9d1SAndroid Build Coastguard Worker //    notice, this list of conditions and the following disclaimer.
20*bbecb9d1SAndroid Build Coastguard Worker // 2. Redistributions in binary form must reproduce the above copyright
21*bbecb9d1SAndroid Build Coastguard Worker //    notice, this list of conditions and the following disclaimer in the
22*bbecb9d1SAndroid Build Coastguard Worker //    documentation and/or other materials provided with the distribution.
23*bbecb9d1SAndroid Build Coastguard Worker // 3. Neither the name of the project nor the names of its contributors
24*bbecb9d1SAndroid Build Coastguard Worker //    may be used to endorse or promote products derived from this software
25*bbecb9d1SAndroid Build Coastguard Worker //    without specific prior written permission.
26*bbecb9d1SAndroid Build Coastguard Worker //
27*bbecb9d1SAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
28*bbecb9d1SAndroid Build Coastguard Worker // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29*bbecb9d1SAndroid Build Coastguard Worker // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30*bbecb9d1SAndroid Build Coastguard Worker // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
31*bbecb9d1SAndroid Build Coastguard Worker // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32*bbecb9d1SAndroid Build Coastguard Worker // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33*bbecb9d1SAndroid Build Coastguard Worker // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34*bbecb9d1SAndroid Build Coastguard Worker // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35*bbecb9d1SAndroid Build Coastguard Worker // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36*bbecb9d1SAndroid Build Coastguard Worker // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37*bbecb9d1SAndroid Build Coastguard Worker // SUCH DAMAGE.
38*bbecb9d1SAndroid Build Coastguard Worker //
39*bbecb9d1SAndroid Build Coastguard Worker 
40*bbecb9d1SAndroid Build Coastguard Worker #include <assert.h>
41*bbecb9d1SAndroid Build Coastguard Worker #include <string.h>
42*bbecb9d1SAndroid Build Coastguard Worker #include <stdlib.h>
43*bbecb9d1SAndroid Build Coastguard Worker #include <stdbool.h>
44*bbecb9d1SAndroid Build Coastguard Worker #include "vrend_iov.h"
45*bbecb9d1SAndroid Build Coastguard Worker 
vrend_get_iovec_size(const struct iovec * iov,int iovlen)46*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_get_iovec_size(const struct iovec *iov, int iovlen) {
47*bbecb9d1SAndroid Build Coastguard Worker   size_t size = 0;
48*bbecb9d1SAndroid Build Coastguard Worker 
49*bbecb9d1SAndroid Build Coastguard Worker   while (iovlen > 0) {
50*bbecb9d1SAndroid Build Coastguard Worker     size += iov->iov_len;
51*bbecb9d1SAndroid Build Coastguard Worker     iov++;
52*bbecb9d1SAndroid Build Coastguard Worker     iovlen--;
53*bbecb9d1SAndroid Build Coastguard Worker   }
54*bbecb9d1SAndroid Build Coastguard Worker 
55*bbecb9d1SAndroid Build Coastguard Worker   return size;
56*bbecb9d1SAndroid Build Coastguard Worker }
57*bbecb9d1SAndroid Build Coastguard Worker 
vrend_read_from_iovec(const struct iovec * iov,int iovlen,size_t offset,char * buf,size_t count)58*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_read_from_iovec(const struct iovec *iov, int iovlen,
59*bbecb9d1SAndroid Build Coastguard Worker 			     size_t offset,
60*bbecb9d1SAndroid Build Coastguard Worker 			     char *buf, size_t count)
61*bbecb9d1SAndroid Build Coastguard Worker {
62*bbecb9d1SAndroid Build Coastguard Worker   size_t read = 0;
63*bbecb9d1SAndroid Build Coastguard Worker   size_t len;
64*bbecb9d1SAndroid Build Coastguard Worker 
65*bbecb9d1SAndroid Build Coastguard Worker   while (count > 0 && iovlen > 0) {
66*bbecb9d1SAndroid Build Coastguard Worker     if (iov->iov_len > offset) {
67*bbecb9d1SAndroid Build Coastguard Worker       len = iov->iov_len - offset;
68*bbecb9d1SAndroid Build Coastguard Worker 
69*bbecb9d1SAndroid Build Coastguard Worker       if (count < len) len = count;
70*bbecb9d1SAndroid Build Coastguard Worker 
71*bbecb9d1SAndroid Build Coastguard Worker       memcpy(buf, (char*)iov->iov_base + offset, len);
72*bbecb9d1SAndroid Build Coastguard Worker       read += len;
73*bbecb9d1SAndroid Build Coastguard Worker 
74*bbecb9d1SAndroid Build Coastguard Worker       buf += len;
75*bbecb9d1SAndroid Build Coastguard Worker       count -= len;
76*bbecb9d1SAndroid Build Coastguard Worker       offset = 0;
77*bbecb9d1SAndroid Build Coastguard Worker     } else {
78*bbecb9d1SAndroid Build Coastguard Worker       offset -= iov->iov_len;
79*bbecb9d1SAndroid Build Coastguard Worker     }
80*bbecb9d1SAndroid Build Coastguard Worker 
81*bbecb9d1SAndroid Build Coastguard Worker     iov++;
82*bbecb9d1SAndroid Build Coastguard Worker     iovlen--;
83*bbecb9d1SAndroid Build Coastguard Worker   }
84*bbecb9d1SAndroid Build Coastguard Worker     assert(offset == 0);
85*bbecb9d1SAndroid Build Coastguard Worker   return read;
86*bbecb9d1SAndroid Build Coastguard Worker }
87*bbecb9d1SAndroid Build Coastguard Worker 
vrend_write_to_iovec(const struct iovec * iov,int iovlen,size_t offset,const char * buf,size_t count)88*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_write_to_iovec(const struct iovec *iov, int iovlen,
89*bbecb9d1SAndroid Build Coastguard Worker 			 size_t offset, const char *buf, size_t count)
90*bbecb9d1SAndroid Build Coastguard Worker {
91*bbecb9d1SAndroid Build Coastguard Worker   size_t written = 0;
92*bbecb9d1SAndroid Build Coastguard Worker   size_t len;
93*bbecb9d1SAndroid Build Coastguard Worker 
94*bbecb9d1SAndroid Build Coastguard Worker   while (count > 0 && iovlen > 0) {
95*bbecb9d1SAndroid Build Coastguard Worker     if (iov->iov_len > offset) {
96*bbecb9d1SAndroid Build Coastguard Worker       len = iov->iov_len - offset;
97*bbecb9d1SAndroid Build Coastguard Worker 
98*bbecb9d1SAndroid Build Coastguard Worker       if (count < len) len = count;
99*bbecb9d1SAndroid Build Coastguard Worker 
100*bbecb9d1SAndroid Build Coastguard Worker       memcpy((char*)iov->iov_base + offset, buf, len);
101*bbecb9d1SAndroid Build Coastguard Worker       written += len;
102*bbecb9d1SAndroid Build Coastguard Worker 
103*bbecb9d1SAndroid Build Coastguard Worker       offset = 0;
104*bbecb9d1SAndroid Build Coastguard Worker       buf += len;
105*bbecb9d1SAndroid Build Coastguard Worker       count -= len;
106*bbecb9d1SAndroid Build Coastguard Worker     } else {
107*bbecb9d1SAndroid Build Coastguard Worker       offset -= iov->iov_len;
108*bbecb9d1SAndroid Build Coastguard Worker     }
109*bbecb9d1SAndroid Build Coastguard Worker     iov++;
110*bbecb9d1SAndroid Build Coastguard Worker     iovlen--;
111*bbecb9d1SAndroid Build Coastguard Worker   }
112*bbecb9d1SAndroid Build Coastguard Worker     assert(offset == 0);
113*bbecb9d1SAndroid Build Coastguard Worker   return written;
114*bbecb9d1SAndroid Build Coastguard Worker }
115*bbecb9d1SAndroid Build Coastguard Worker 
vrend_read_from_iovec_cb(const struct iovec * iov,int iovlen,size_t offset,size_t count,iov_cb iocb,void * cookie)116*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_read_from_iovec_cb(const struct iovec *iov, int iovlen,
117*bbecb9d1SAndroid Build Coastguard Worker 				size_t offset, size_t count,
118*bbecb9d1SAndroid Build Coastguard Worker 				iov_cb iocb, void *cookie)
119*bbecb9d1SAndroid Build Coastguard Worker {
120*bbecb9d1SAndroid Build Coastguard Worker   size_t read = 0;
121*bbecb9d1SAndroid Build Coastguard Worker   size_t len;
122*bbecb9d1SAndroid Build Coastguard Worker 
123*bbecb9d1SAndroid Build Coastguard Worker   while (count > 0 && iovlen > 0) {
124*bbecb9d1SAndroid Build Coastguard Worker     if (iov->iov_len > offset) {
125*bbecb9d1SAndroid Build Coastguard Worker       len = iov->iov_len - offset;
126*bbecb9d1SAndroid Build Coastguard Worker 
127*bbecb9d1SAndroid Build Coastguard Worker       if (count < len) len = count;
128*bbecb9d1SAndroid Build Coastguard Worker 
129*bbecb9d1SAndroid Build Coastguard Worker       (*iocb)(cookie, read, (char*)iov->iov_base + offset, len);
130*bbecb9d1SAndroid Build Coastguard Worker       read += len;
131*bbecb9d1SAndroid Build Coastguard Worker 
132*bbecb9d1SAndroid Build Coastguard Worker       count -= len;
133*bbecb9d1SAndroid Build Coastguard Worker       offset = 0;
134*bbecb9d1SAndroid Build Coastguard Worker     } else {
135*bbecb9d1SAndroid Build Coastguard Worker       offset -= iov->iov_len;
136*bbecb9d1SAndroid Build Coastguard Worker     }
137*bbecb9d1SAndroid Build Coastguard Worker     iov++;
138*bbecb9d1SAndroid Build Coastguard Worker     iovlen--;
139*bbecb9d1SAndroid Build Coastguard Worker   }
140*bbecb9d1SAndroid Build Coastguard Worker     assert(offset == 0);
141*bbecb9d1SAndroid Build Coastguard Worker   return read;
142*bbecb9d1SAndroid Build Coastguard Worker 
143*bbecb9d1SAndroid Build Coastguard Worker 
144*bbecb9d1SAndroid Build Coastguard Worker }
145*bbecb9d1SAndroid Build Coastguard Worker 
146*bbecb9d1SAndroid Build Coastguard Worker /**
147*bbecb9d1SAndroid Build Coastguard Worker  * Copy data from one iovec to another iovec.
148*bbecb9d1SAndroid Build Coastguard Worker  *
149*bbecb9d1SAndroid Build Coastguard Worker  * TODO: Implement iovec copy without copy to intermediate buffer.
150*bbecb9d1SAndroid Build Coastguard Worker  *
151*bbecb9d1SAndroid Build Coastguard Worker  * \param src_iov    The source iov.
152*bbecb9d1SAndroid Build Coastguard Worker  * \param src_iovlen The number of memory regions in the source iov.
153*bbecb9d1SAndroid Build Coastguard Worker  * \param src_offset The byte offset in the source iov to start reading from.
154*bbecb9d1SAndroid Build Coastguard Worker  * \param dst_iov    The destination iov.
155*bbecb9d1SAndroid Build Coastguard Worker  * \param dst_iovlen The number of memory regions in the destination iov.
156*bbecb9d1SAndroid Build Coastguard Worker  * \param dst_offset The byte offset in the destination iov to start writing to.
157*bbecb9d1SAndroid Build Coastguard Worker  * \param count      The number of bytes to copy
158*bbecb9d1SAndroid Build Coastguard Worker  * \param buf        If not NULL, a pointer to a buffer of at least count size
159*bbecb9d1SAndroid Build Coastguard Worker  *                   to use a temporary storage for the copy operation.
160*bbecb9d1SAndroid Build Coastguard Worker  * \return           -1 on failure, 0 on success
161*bbecb9d1SAndroid Build Coastguard Worker  */
vrend_copy_iovec(const struct iovec * src_iov,int src_iovlen,size_t src_offset,const struct iovec * dst_iov,int dst_iovlen,size_t dst_offset,size_t count,char * buf)162*bbecb9d1SAndroid Build Coastguard Worker int vrend_copy_iovec(const struct iovec *src_iov, int src_iovlen, size_t src_offset,
163*bbecb9d1SAndroid Build Coastguard Worker 		     const struct iovec *dst_iov, int dst_iovlen, size_t dst_offset,
164*bbecb9d1SAndroid Build Coastguard Worker 		     size_t count, char *buf)
165*bbecb9d1SAndroid Build Coastguard Worker {
166*bbecb9d1SAndroid Build Coastguard Worker   int ret = 0;
167*bbecb9d1SAndroid Build Coastguard Worker   bool needs_free;
168*bbecb9d1SAndroid Build Coastguard Worker   size_t nread;
169*bbecb9d1SAndroid Build Coastguard Worker   size_t nwritten;
170*bbecb9d1SAndroid Build Coastguard Worker 
171*bbecb9d1SAndroid Build Coastguard Worker   if (src_iov == NULL || dst_iov == NULL)
172*bbecb9d1SAndroid Build Coastguard Worker     return -1;
173*bbecb9d1SAndroid Build Coastguard Worker 
174*bbecb9d1SAndroid Build Coastguard Worker   if (src_iov == dst_iov && src_offset == dst_offset)
175*bbecb9d1SAndroid Build Coastguard Worker     return 0;
176*bbecb9d1SAndroid Build Coastguard Worker 
177*bbecb9d1SAndroid Build Coastguard Worker   if (!buf) {
178*bbecb9d1SAndroid Build Coastguard Worker     buf = malloc(count);
179*bbecb9d1SAndroid Build Coastguard Worker     needs_free = true;
180*bbecb9d1SAndroid Build Coastguard Worker   } else {
181*bbecb9d1SAndroid Build Coastguard Worker     needs_free = false;
182*bbecb9d1SAndroid Build Coastguard Worker   }
183*bbecb9d1SAndroid Build Coastguard Worker 
184*bbecb9d1SAndroid Build Coastguard Worker   if (!buf)
185*bbecb9d1SAndroid Build Coastguard Worker     return -1;
186*bbecb9d1SAndroid Build Coastguard Worker 
187*bbecb9d1SAndroid Build Coastguard Worker   nread = vrend_read_from_iovec(src_iov, src_iovlen, src_offset, buf, count);
188*bbecb9d1SAndroid Build Coastguard Worker   if (nread != count) {
189*bbecb9d1SAndroid Build Coastguard Worker     ret = -1;
190*bbecb9d1SAndroid Build Coastguard Worker     goto out;
191*bbecb9d1SAndroid Build Coastguard Worker   }
192*bbecb9d1SAndroid Build Coastguard Worker 
193*bbecb9d1SAndroid Build Coastguard Worker   nwritten = vrend_write_to_iovec(dst_iov, dst_iovlen, dst_offset, buf, count);
194*bbecb9d1SAndroid Build Coastguard Worker   if (nwritten != count) {
195*bbecb9d1SAndroid Build Coastguard Worker     ret = -1;
196*bbecb9d1SAndroid Build Coastguard Worker     goto out;
197*bbecb9d1SAndroid Build Coastguard Worker   }
198*bbecb9d1SAndroid Build Coastguard Worker 
199*bbecb9d1SAndroid Build Coastguard Worker out:
200*bbecb9d1SAndroid Build Coastguard Worker   if (needs_free)
201*bbecb9d1SAndroid Build Coastguard Worker     free(buf);
202*bbecb9d1SAndroid Build Coastguard Worker 
203*bbecb9d1SAndroid Build Coastguard Worker   return ret;
204*bbecb9d1SAndroid Build Coastguard Worker }
205