xref: /aosp_15_r20/external/mesa3d/src/gfxstream/guest/connection-manager/VirtioGpuPipeStream.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright 2018 Google LLC
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker #include "VirtioGpuPipeStream.h"
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker #include <errno.h>
9*61046927SAndroid Build Coastguard Worker #include <sys/mman.h>
10*61046927SAndroid Build Coastguard Worker #include <sys/types.h>
11*61046927SAndroid Build Coastguard Worker #include <unistd.h>
12*61046927SAndroid Build Coastguard Worker 
13*61046927SAndroid Build Coastguard Worker #include <cstring>
14*61046927SAndroid Build Coastguard Worker #include <string>
15*61046927SAndroid Build Coastguard Worker 
16*61046927SAndroid Build Coastguard Worker #include "VirtGpu.h"
17*61046927SAndroid Build Coastguard Worker #include "util/log.h"
18*61046927SAndroid Build Coastguard Worker 
19*61046927SAndroid Build Coastguard Worker static const size_t kTransferBufferSize = (1048576);
20*61046927SAndroid Build Coastguard Worker 
21*61046927SAndroid Build Coastguard Worker static const size_t kReadSize = 512 * 1024;
22*61046927SAndroid Build Coastguard Worker static const size_t kWriteOffset = kReadSize;
23*61046927SAndroid Build Coastguard Worker 
VirtioGpuPipeStream(size_t bufSize,int32_t descriptor)24*61046927SAndroid Build Coastguard Worker VirtioGpuPipeStream::VirtioGpuPipeStream(size_t bufSize, int32_t descriptor)
25*61046927SAndroid Build Coastguard Worker     : IOStream(bufSize),
26*61046927SAndroid Build Coastguard Worker       m_fd(descriptor),
27*61046927SAndroid Build Coastguard Worker       m_virtio_mapped(nullptr),
28*61046927SAndroid Build Coastguard Worker       m_bufsize(bufSize),
29*61046927SAndroid Build Coastguard Worker       m_buf(nullptr),
30*61046927SAndroid Build Coastguard Worker       m_writtenPos(0) {}
31*61046927SAndroid Build Coastguard Worker 
~VirtioGpuPipeStream()32*61046927SAndroid Build Coastguard Worker VirtioGpuPipeStream::~VirtioGpuPipeStream() { free(m_buf); }
33*61046927SAndroid Build Coastguard Worker 
valid()34*61046927SAndroid Build Coastguard Worker bool VirtioGpuPipeStream::valid() { return m_device != nullptr; }
35*61046927SAndroid Build Coastguard Worker 
getRendernodeFd()36*61046927SAndroid Build Coastguard Worker int VirtioGpuPipeStream::getRendernodeFd() {
37*61046927SAndroid Build Coastguard Worker     if (m_device == nullptr) {
38*61046927SAndroid Build Coastguard Worker         return -1;
39*61046927SAndroid Build Coastguard Worker     }
40*61046927SAndroid Build Coastguard Worker     return m_device->getDeviceHandle();
41*61046927SAndroid Build Coastguard Worker }
42*61046927SAndroid Build Coastguard Worker 
connect(const char * serviceName)43*61046927SAndroid Build Coastguard Worker int VirtioGpuPipeStream::connect(const char* serviceName) {
44*61046927SAndroid Build Coastguard Worker     if (!m_device) {
45*61046927SAndroid Build Coastguard Worker         m_device.reset(createPlatformVirtGpuDevice(kCapsetNone, m_fd));
46*61046927SAndroid Build Coastguard Worker         if (!m_device) {
47*61046927SAndroid Build Coastguard Worker             mesa_loge("Failed to create VirtioGpuPipeStream VirtGpuDevice.");
48*61046927SAndroid Build Coastguard Worker             return -1;
49*61046927SAndroid Build Coastguard Worker         }
50*61046927SAndroid Build Coastguard Worker 
51*61046927SAndroid Build Coastguard Worker         m_resource = m_device->createResource(/*width=*/kTransferBufferSize,
52*61046927SAndroid Build Coastguard Worker                                               /*height=*/1,
53*61046927SAndroid Build Coastguard Worker                                               /*stride=*/kTransferBufferSize,
54*61046927SAndroid Build Coastguard Worker                                               /*size=*/kTransferBufferSize, VIRGL_FORMAT_R8_UNORM,
55*61046927SAndroid Build Coastguard Worker                                               PIPE_BUFFER, VIRGL_BIND_CUSTOM);
56*61046927SAndroid Build Coastguard Worker         if (!m_resource) {
57*61046927SAndroid Build Coastguard Worker             mesa_loge("Failed to create VirtioGpuPipeStream resource.");
58*61046927SAndroid Build Coastguard Worker             return -1;
59*61046927SAndroid Build Coastguard Worker         }
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker         m_resourceMapping = m_resource->createMapping();
62*61046927SAndroid Build Coastguard Worker         if (!m_resourceMapping) {
63*61046927SAndroid Build Coastguard Worker             mesa_loge("Failed to create VirtioGpuPipeStream resource mapping.");
64*61046927SAndroid Build Coastguard Worker             return -1;
65*61046927SAndroid Build Coastguard Worker         }
66*61046927SAndroid Build Coastguard Worker 
67*61046927SAndroid Build Coastguard Worker         m_virtio_mapped = m_resourceMapping->asRawPtr();
68*61046927SAndroid Build Coastguard Worker         if (!m_virtio_mapped) {
69*61046927SAndroid Build Coastguard Worker             mesa_loge("Failed to create VirtioGpuPipeStream resource mapping ptr.");
70*61046927SAndroid Build Coastguard Worker             return -1;
71*61046927SAndroid Build Coastguard Worker         }
72*61046927SAndroid Build Coastguard Worker     }
73*61046927SAndroid Build Coastguard Worker 
74*61046927SAndroid Build Coastguard Worker     wait();
75*61046927SAndroid Build Coastguard Worker 
76*61046927SAndroid Build Coastguard Worker     if (serviceName) {
77*61046927SAndroid Build Coastguard Worker         writeFully(serviceName, strlen(serviceName) + 1);
78*61046927SAndroid Build Coastguard Worker     } else {
79*61046927SAndroid Build Coastguard Worker         static const char kPipeString[] = "pipe:opengles";
80*61046927SAndroid Build Coastguard Worker         std::string pipeStr(kPipeString);
81*61046927SAndroid Build Coastguard Worker         writeFully(kPipeString, sizeof(kPipeString));
82*61046927SAndroid Build Coastguard Worker     }
83*61046927SAndroid Build Coastguard Worker 
84*61046927SAndroid Build Coastguard Worker     return 0;
85*61046927SAndroid Build Coastguard Worker }
86*61046927SAndroid Build Coastguard Worker 
processPipeInit()87*61046927SAndroid Build Coastguard Worker uint64_t VirtioGpuPipeStream::processPipeInit() {
88*61046927SAndroid Build Coastguard Worker     connect("pipe:GLProcessPipe");
89*61046927SAndroid Build Coastguard Worker     int32_t confirmInt = 100;
90*61046927SAndroid Build Coastguard Worker     writeFully(&confirmInt, sizeof(confirmInt));
91*61046927SAndroid Build Coastguard Worker     uint64_t res;
92*61046927SAndroid Build Coastguard Worker     readFully(&res, sizeof(res));
93*61046927SAndroid Build Coastguard Worker     return res;
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker 
allocBuffer(size_t minSize)96*61046927SAndroid Build Coastguard Worker void* VirtioGpuPipeStream::allocBuffer(size_t minSize) {
97*61046927SAndroid Build Coastguard Worker     size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
98*61046927SAndroid Build Coastguard Worker     if (!m_buf) {
99*61046927SAndroid Build Coastguard Worker         m_buf = (unsigned char*)malloc(allocSize);
100*61046927SAndroid Build Coastguard Worker     } else if (m_bufsize < allocSize) {
101*61046927SAndroid Build Coastguard Worker         unsigned char* p = (unsigned char*)realloc(m_buf, allocSize);
102*61046927SAndroid Build Coastguard Worker         if (p != NULL) {
103*61046927SAndroid Build Coastguard Worker             m_buf = p;
104*61046927SAndroid Build Coastguard Worker             m_bufsize = allocSize;
105*61046927SAndroid Build Coastguard Worker         } else {
106*61046927SAndroid Build Coastguard Worker             mesa_loge("realloc (%zu) failed\n", allocSize);
107*61046927SAndroid Build Coastguard Worker             free(m_buf);
108*61046927SAndroid Build Coastguard Worker             m_buf = NULL;
109*61046927SAndroid Build Coastguard Worker             m_bufsize = 0;
110*61046927SAndroid Build Coastguard Worker         }
111*61046927SAndroid Build Coastguard Worker     }
112*61046927SAndroid Build Coastguard Worker 
113*61046927SAndroid Build Coastguard Worker     return m_buf;
114*61046927SAndroid Build Coastguard Worker }
115*61046927SAndroid Build Coastguard Worker 
commitBuffer(size_t size)116*61046927SAndroid Build Coastguard Worker int VirtioGpuPipeStream::commitBuffer(size_t size) {
117*61046927SAndroid Build Coastguard Worker     if (size == 0) return 0;
118*61046927SAndroid Build Coastguard Worker     return writeFully(m_buf, size);
119*61046927SAndroid Build Coastguard Worker }
120*61046927SAndroid Build Coastguard Worker 
writeFully(const void * buf,size_t len)121*61046927SAndroid Build Coastguard Worker int VirtioGpuPipeStream::writeFully(const void* buf, size_t len) {
122*61046927SAndroid Build Coastguard Worker     // DBG(">> VirtioGpuPipeStream::writeFully %d\n", len);
123*61046927SAndroid Build Coastguard Worker     if (!valid()) return -1;
124*61046927SAndroid Build Coastguard Worker     if (!buf) {
125*61046927SAndroid Build Coastguard Worker         if (len > 0) {
126*61046927SAndroid Build Coastguard Worker             // If len is non-zero, buf must not be NULL. Otherwise the pipe would be
127*61046927SAndroid Build Coastguard Worker             // in a corrupted state, which is lethal for the emulator.
128*61046927SAndroid Build Coastguard Worker             mesa_loge(
129*61046927SAndroid Build Coastguard Worker                 "VirtioGpuPipeStream::writeFully failed, buf=NULL, len %zu,"
130*61046927SAndroid Build Coastguard Worker                 " lethal error, exiting",
131*61046927SAndroid Build Coastguard Worker                 len);
132*61046927SAndroid Build Coastguard Worker             abort();
133*61046927SAndroid Build Coastguard Worker         }
134*61046927SAndroid Build Coastguard Worker         return 0;
135*61046927SAndroid Build Coastguard Worker     }
136*61046927SAndroid Build Coastguard Worker 
137*61046927SAndroid Build Coastguard Worker     size_t res = len;
138*61046927SAndroid Build Coastguard Worker     int retval = 0;
139*61046927SAndroid Build Coastguard Worker 
140*61046927SAndroid Build Coastguard Worker     while (res > 0) {
141*61046927SAndroid Build Coastguard Worker         ssize_t stat = transferToHost((const char*)(buf) + (len - res), res);
142*61046927SAndroid Build Coastguard Worker         if (stat > 0) {
143*61046927SAndroid Build Coastguard Worker             res -= stat;
144*61046927SAndroid Build Coastguard Worker             continue;
145*61046927SAndroid Build Coastguard Worker         }
146*61046927SAndroid Build Coastguard Worker         if (stat == 0) { /* EOF */
147*61046927SAndroid Build Coastguard Worker             mesa_loge("VirtioGpuPipeStream::writeFully failed: premature EOF\n");
148*61046927SAndroid Build Coastguard Worker             retval = -1;
149*61046927SAndroid Build Coastguard Worker             break;
150*61046927SAndroid Build Coastguard Worker         }
151*61046927SAndroid Build Coastguard Worker         if (errno == EAGAIN) {
152*61046927SAndroid Build Coastguard Worker             continue;
153*61046927SAndroid Build Coastguard Worker         }
154*61046927SAndroid Build Coastguard Worker         retval = stat;
155*61046927SAndroid Build Coastguard Worker         mesa_loge("VirtioGpuPipeStream::writeFully failed: %s, lethal error, exiting.\n",
156*61046927SAndroid Build Coastguard Worker                   strerror(errno));
157*61046927SAndroid Build Coastguard Worker         abort();
158*61046927SAndroid Build Coastguard Worker     }
159*61046927SAndroid Build Coastguard Worker     // DBG("<< VirtioGpuPipeStream::writeFully %d\n", len );
160*61046927SAndroid Build Coastguard Worker     return retval;
161*61046927SAndroid Build Coastguard Worker }
162*61046927SAndroid Build Coastguard Worker 
readFully(void * buf,size_t len)163*61046927SAndroid Build Coastguard Worker const unsigned char* VirtioGpuPipeStream::readFully(void* buf, size_t len) {
164*61046927SAndroid Build Coastguard Worker     flush();
165*61046927SAndroid Build Coastguard Worker 
166*61046927SAndroid Build Coastguard Worker     if (!valid()) return NULL;
167*61046927SAndroid Build Coastguard Worker     if (!buf) {
168*61046927SAndroid Build Coastguard Worker         if (len > 0) {
169*61046927SAndroid Build Coastguard Worker             // If len is non-zero, buf must not be NULL. Otherwise the pipe would be
170*61046927SAndroid Build Coastguard Worker             // in a corrupted state, which is lethal for the emulator.
171*61046927SAndroid Build Coastguard Worker             mesa_loge(
172*61046927SAndroid Build Coastguard Worker                 "VirtioGpuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
173*61046927SAndroid Build Coastguard Worker                 " error, exiting.",
174*61046927SAndroid Build Coastguard Worker                 len);
175*61046927SAndroid Build Coastguard Worker             abort();
176*61046927SAndroid Build Coastguard Worker         }
177*61046927SAndroid Build Coastguard Worker     }
178*61046927SAndroid Build Coastguard Worker 
179*61046927SAndroid Build Coastguard Worker     size_t res = len;
180*61046927SAndroid Build Coastguard Worker     while (res > 0) {
181*61046927SAndroid Build Coastguard Worker         ssize_t stat = transferFromHost((char*)(buf) + len - res, res);
182*61046927SAndroid Build Coastguard Worker         if (stat == 0) {
183*61046927SAndroid Build Coastguard Worker             // client shutdown;
184*61046927SAndroid Build Coastguard Worker             return NULL;
185*61046927SAndroid Build Coastguard Worker         } else if (stat < 0) {
186*61046927SAndroid Build Coastguard Worker             if (errno == EAGAIN) {
187*61046927SAndroid Build Coastguard Worker                 continue;
188*61046927SAndroid Build Coastguard Worker             } else {
189*61046927SAndroid Build Coastguard Worker                 mesa_loge(
190*61046927SAndroid Build Coastguard Worker                     "VirtioGpuPipeStream::readFully failed (buf %p, len %zu"
191*61046927SAndroid Build Coastguard Worker                     ", res %zu): %s, lethal error, exiting.",
192*61046927SAndroid Build Coastguard Worker                     buf, len, res, strerror(errno));
193*61046927SAndroid Build Coastguard Worker                 abort();
194*61046927SAndroid Build Coastguard Worker             }
195*61046927SAndroid Build Coastguard Worker         } else {
196*61046927SAndroid Build Coastguard Worker             res -= stat;
197*61046927SAndroid Build Coastguard Worker         }
198*61046927SAndroid Build Coastguard Worker     }
199*61046927SAndroid Build Coastguard Worker     // DBG("<< VirtioGpuPipeStream::readFully %d\n", len);
200*61046927SAndroid Build Coastguard Worker     return (const unsigned char*)buf;
201*61046927SAndroid Build Coastguard Worker }
202*61046927SAndroid Build Coastguard Worker 
commitBufferAndReadFully(size_t writeSize,void * userReadBufPtr,size_t totalReadSize)203*61046927SAndroid Build Coastguard Worker const unsigned char* VirtioGpuPipeStream::commitBufferAndReadFully(size_t writeSize,
204*61046927SAndroid Build Coastguard Worker                                                                    void* userReadBufPtr,
205*61046927SAndroid Build Coastguard Worker                                                                    size_t totalReadSize) {
206*61046927SAndroid Build Coastguard Worker     return commitBuffer(writeSize) ? nullptr : readFully(userReadBufPtr, totalReadSize);
207*61046927SAndroid Build Coastguard Worker }
208*61046927SAndroid Build Coastguard Worker 
read(void * buf,size_t * inout_len)209*61046927SAndroid Build Coastguard Worker const unsigned char* VirtioGpuPipeStream::read(void* buf, size_t* inout_len) {
210*61046927SAndroid Build Coastguard Worker     // DBG(">> VirtioGpuPipeStream::read %d\n", *inout_len);
211*61046927SAndroid Build Coastguard Worker     if (!valid()) return NULL;
212*61046927SAndroid Build Coastguard Worker     if (!buf) {
213*61046927SAndroid Build Coastguard Worker         mesa_loge("VirtioGpuPipeStream::read failed, buf=NULL");
214*61046927SAndroid Build Coastguard Worker         return NULL;  // do not allow NULL buf in that implementation
215*61046927SAndroid Build Coastguard Worker     }
216*61046927SAndroid Build Coastguard Worker 
217*61046927SAndroid Build Coastguard Worker     int n = recv(buf, *inout_len);
218*61046927SAndroid Build Coastguard Worker 
219*61046927SAndroid Build Coastguard Worker     if (n > 0) {
220*61046927SAndroid Build Coastguard Worker         *inout_len = n;
221*61046927SAndroid Build Coastguard Worker         return (const unsigned char*)buf;
222*61046927SAndroid Build Coastguard Worker     }
223*61046927SAndroid Build Coastguard Worker 
224*61046927SAndroid Build Coastguard Worker     // DBG("<< VirtioGpuPipeStream::read %d\n", *inout_len);
225*61046927SAndroid Build Coastguard Worker     return NULL;
226*61046927SAndroid Build Coastguard Worker }
227*61046927SAndroid Build Coastguard Worker 
recv(void * buf,size_t len)228*61046927SAndroid Build Coastguard Worker int VirtioGpuPipeStream::recv(void* buf, size_t len) {
229*61046927SAndroid Build Coastguard Worker     if (!valid()) return -EINVAL;
230*61046927SAndroid Build Coastguard Worker     char* p = (char*)buf;
231*61046927SAndroid Build Coastguard Worker     int ret = 0;
232*61046927SAndroid Build Coastguard Worker     while (len > 0) {
233*61046927SAndroid Build Coastguard Worker         int res = transferFromHost(p, len);
234*61046927SAndroid Build Coastguard Worker         if (res > 0) {
235*61046927SAndroid Build Coastguard Worker             p += res;
236*61046927SAndroid Build Coastguard Worker             ret += res;
237*61046927SAndroid Build Coastguard Worker             len -= res;
238*61046927SAndroid Build Coastguard Worker             continue;
239*61046927SAndroid Build Coastguard Worker         }
240*61046927SAndroid Build Coastguard Worker         if (res == 0) { /* EOF */
241*61046927SAndroid Build Coastguard Worker             break;
242*61046927SAndroid Build Coastguard Worker         }
243*61046927SAndroid Build Coastguard Worker         if (errno != EAGAIN) {
244*61046927SAndroid Build Coastguard Worker             continue;
245*61046927SAndroid Build Coastguard Worker         }
246*61046927SAndroid Build Coastguard Worker 
247*61046927SAndroid Build Coastguard Worker         /* A real error */
248*61046927SAndroid Build Coastguard Worker         if (ret == 0) ret = -1;
249*61046927SAndroid Build Coastguard Worker         break;
250*61046927SAndroid Build Coastguard Worker     }
251*61046927SAndroid Build Coastguard Worker     return ret;
252*61046927SAndroid Build Coastguard Worker }
253*61046927SAndroid Build Coastguard Worker 
wait()254*61046927SAndroid Build Coastguard Worker void VirtioGpuPipeStream::wait() {
255*61046927SAndroid Build Coastguard Worker     int ret = m_resource->wait();
256*61046927SAndroid Build Coastguard Worker     if (ret) {
257*61046927SAndroid Build Coastguard Worker         mesa_loge("VirtioGpuPipeStream: DRM_IOCTL_VIRTGPU_WAIT failed with %d (%s)\n", errno,
258*61046927SAndroid Build Coastguard Worker                   strerror(errno));
259*61046927SAndroid Build Coastguard Worker     }
260*61046927SAndroid Build Coastguard Worker 
261*61046927SAndroid Build Coastguard Worker     m_writtenPos = 0;
262*61046927SAndroid Build Coastguard Worker }
263*61046927SAndroid Build Coastguard Worker 
transferToHost(const void * buffer,size_t len)264*61046927SAndroid Build Coastguard Worker ssize_t VirtioGpuPipeStream::transferToHost(const void* buffer, size_t len) {
265*61046927SAndroid Build Coastguard Worker     size_t todo = len;
266*61046927SAndroid Build Coastguard Worker     size_t done = 0;
267*61046927SAndroid Build Coastguard Worker     int ret = EAGAIN;
268*61046927SAndroid Build Coastguard Worker 
269*61046927SAndroid Build Coastguard Worker     unsigned char* virtioPtr = m_virtio_mapped;
270*61046927SAndroid Build Coastguard Worker 
271*61046927SAndroid Build Coastguard Worker     const unsigned char* readPtr = reinterpret_cast<const unsigned char*>(buffer);
272*61046927SAndroid Build Coastguard Worker 
273*61046927SAndroid Build Coastguard Worker     while (done < len) {
274*61046927SAndroid Build Coastguard Worker         size_t toXfer = todo > kTransferBufferSize ? kTransferBufferSize : todo;
275*61046927SAndroid Build Coastguard Worker 
276*61046927SAndroid Build Coastguard Worker         if (toXfer > (kTransferBufferSize - m_writtenPos)) {
277*61046927SAndroid Build Coastguard Worker             wait();
278*61046927SAndroid Build Coastguard Worker         }
279*61046927SAndroid Build Coastguard Worker 
280*61046927SAndroid Build Coastguard Worker         memcpy(virtioPtr + m_writtenPos, readPtr, toXfer);
281*61046927SAndroid Build Coastguard Worker 
282*61046927SAndroid Build Coastguard Worker         ret = m_resource->transferToHost(m_writtenPos, toXfer);
283*61046927SAndroid Build Coastguard Worker         if (ret) {
284*61046927SAndroid Build Coastguard Worker             mesa_loge("VirtioGpuPipeStream: failed to transferToHost() with errno %d (%s)\n", errno,
285*61046927SAndroid Build Coastguard Worker                       strerror(errno));
286*61046927SAndroid Build Coastguard Worker             return (ssize_t)ret;
287*61046927SAndroid Build Coastguard Worker         }
288*61046927SAndroid Build Coastguard Worker 
289*61046927SAndroid Build Coastguard Worker         done += toXfer;
290*61046927SAndroid Build Coastguard Worker         readPtr += toXfer;
291*61046927SAndroid Build Coastguard Worker         todo -= toXfer;
292*61046927SAndroid Build Coastguard Worker         m_writtenPos += toXfer;
293*61046927SAndroid Build Coastguard Worker     }
294*61046927SAndroid Build Coastguard Worker 
295*61046927SAndroid Build Coastguard Worker     return len;
296*61046927SAndroid Build Coastguard Worker }
297*61046927SAndroid Build Coastguard Worker 
transferFromHost(void * buffer,size_t len)298*61046927SAndroid Build Coastguard Worker ssize_t VirtioGpuPipeStream::transferFromHost(void* buffer, size_t len) {
299*61046927SAndroid Build Coastguard Worker     size_t todo = len;
300*61046927SAndroid Build Coastguard Worker     size_t done = 0;
301*61046927SAndroid Build Coastguard Worker     int ret = EAGAIN;
302*61046927SAndroid Build Coastguard Worker 
303*61046927SAndroid Build Coastguard Worker     const unsigned char* virtioPtr = m_virtio_mapped;
304*61046927SAndroid Build Coastguard Worker     unsigned char* readPtr = reinterpret_cast<unsigned char*>(buffer);
305*61046927SAndroid Build Coastguard Worker 
306*61046927SAndroid Build Coastguard Worker     if (m_writtenPos) {
307*61046927SAndroid Build Coastguard Worker         wait();
308*61046927SAndroid Build Coastguard Worker     }
309*61046927SAndroid Build Coastguard Worker 
310*61046927SAndroid Build Coastguard Worker     while (done < len) {
311*61046927SAndroid Build Coastguard Worker         size_t toXfer = todo > kTransferBufferSize ? kTransferBufferSize : todo;
312*61046927SAndroid Build Coastguard Worker 
313*61046927SAndroid Build Coastguard Worker         ret = m_resource->transferFromHost(0, toXfer);
314*61046927SAndroid Build Coastguard Worker         if (ret) {
315*61046927SAndroid Build Coastguard Worker             mesa_loge("VirtioGpuPipeStream: failed to transferFromHost() with errno %d (%s)\n",
316*61046927SAndroid Build Coastguard Worker                       errno, strerror(errno));
317*61046927SAndroid Build Coastguard Worker             return (ssize_t)ret;
318*61046927SAndroid Build Coastguard Worker         }
319*61046927SAndroid Build Coastguard Worker 
320*61046927SAndroid Build Coastguard Worker         wait();
321*61046927SAndroid Build Coastguard Worker 
322*61046927SAndroid Build Coastguard Worker         memcpy(readPtr, virtioPtr, toXfer);
323*61046927SAndroid Build Coastguard Worker 
324*61046927SAndroid Build Coastguard Worker         done += toXfer;
325*61046927SAndroid Build Coastguard Worker         readPtr += toXfer;
326*61046927SAndroid Build Coastguard Worker         todo -= toXfer;
327*61046927SAndroid Build Coastguard Worker     }
328*61046927SAndroid Build Coastguard Worker 
329*61046927SAndroid Build Coastguard Worker     return len;
330*61046927SAndroid Build Coastguard Worker }
331