• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2011 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/utils/panic.h"
13 #include "android/utils/system.h"
14 #include "hw/android/goldfish/pipe.h"
15 #include "hw/android/goldfish/device.h"
16 #include "hw/android/goldfish/vmem.h"
17 #include "qemu/timer.h"
18 
19 #define  DEBUG 0
20 
21 /* Set to 1 to debug i/o register reads/writes */
22 #define DEBUG_REGS  0
23 
24 #if DEBUG >= 1
25 #  define D(...)  fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
26 #else
27 #  define D(...)  (void)0
28 #endif
29 
30 #if DEBUG >= 2
31 #  define DD(...)  fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
32 #else
33 #  define DD(...)  (void)0
34 #endif
35 
36 #if DEBUG_REGS >= 1
37 #  define DR(...)   D(__VA_ARGS__)
38 #else
39 #  define DR(...)   (void)0
40 #endif
41 
42 #define E(...)  fprintf(stderr, "ERROR:" __VA_ARGS__), fprintf(stderr, "\n")
43 
44 /* Set to 1 to enable the 'zero' pipe type, useful for debugging */
45 #define DEBUG_ZERO_PIPE  1
46 
47 /* Set to 1 to enable the 'pingpong' pipe type, useful for debugging */
48 #define DEBUG_PINGPONG_PIPE 1
49 
50 /* Set to 1 to enable the 'throttle' pipe type, useful for debugging */
51 #define DEBUG_THROTTLE_PIPE 1
52 
53 /* Maximum length of pipe service name, in characters (excluding final 0) */
54 #define MAX_PIPE_SERVICE_NAME_SIZE  255
55 
56 #define GOLDFISH_PIPE_SAVE_VERSION  3
57 
58 // Up to Tools r22.6, the emulator saved with this version number.
59 #define GOLDFISH_PIPE_SAVE_VERSION_LEGACY  2
60 
61 /***********************************************************************
62  ***********************************************************************
63  *****
64  *****   P I P E   S E R V I C E   R E G I S T R A T I O N
65  *****
66  *****/
67 
68 #define MAX_PIPE_SERVICES  8
69 typedef struct {
70     const char*        name;
71     void*              opaque;
72     GoldfishPipeFuncs  funcs;
73 } PipeService;
74 
75 typedef struct {
76     int          count;
77     PipeService  services[MAX_PIPE_SERVICES];
78 } PipeServices;
79 
80 static PipeServices  _pipeServices[1];
81 
82 void
goldfish_pipe_add_type(const char * pipeName,void * pipeOpaque,const GoldfishPipeFuncs * pipeFuncs)83 goldfish_pipe_add_type(const char*               pipeName,
84                        void*                     pipeOpaque,
85                        const GoldfishPipeFuncs*  pipeFuncs )
86 {
87     PipeServices* list = _pipeServices;
88     int           count = list->count;
89 
90     if (count >= MAX_PIPE_SERVICES) {
91         APANIC("Too many goldfish pipe services (%d)", count);
92     }
93 
94     if (strlen(pipeName) > MAX_PIPE_SERVICE_NAME_SIZE) {
95         APANIC("Pipe service name too long: '%s'", pipeName);
96     }
97 
98     list->services[count].name   = pipeName;
99     list->services[count].opaque = pipeOpaque;
100     list->services[count].funcs  = pipeFuncs[0];
101 
102     list->count++;
103 }
104 
105 static const PipeService*
goldfish_pipe_find_type(const char * pipeName)106 goldfish_pipe_find_type(const char*  pipeName)
107 {
108     PipeServices* list = _pipeServices;
109     int           count = list->count;
110     int           nn;
111 
112     for (nn = 0; nn < count; nn++) {
113         if (!strcmp(list->services[nn].name, pipeName)) {
114             return &list->services[nn];
115         }
116     }
117     return NULL;
118 }
119 
120 
121 /***********************************************************************
122  ***********************************************************************
123  *****
124  *****    P I P E   C O N N E C T I O N S
125  *****
126  *****/
127 
128 typedef struct PipeDevice  PipeDevice;
129 
130 typedef struct Pipe {
131     struct Pipe*              next;
132     struct Pipe*              next_waked;
133     PipeDevice*                device;
134     uint64_t                   channel;
135     void*                      opaque;
136     const GoldfishPipeFuncs*   funcs;
137     const PipeService*         service;
138     char*                      args;
139     unsigned char              wanted;
140     char                       closed;
141 } Pipe;
142 
143 /* Forward */
144 static void*  pipeConnector_new(Pipe*  pipe);
145 
146 static Pipe*
pipe_new0(PipeDevice * dev)147 pipe_new0(PipeDevice* dev)
148 {
149     Pipe*  pipe;
150     ANEW0(pipe);
151     pipe->device = dev;
152     return pipe;
153 }
154 
155 static Pipe*
pipe_new(uint64_t channel,PipeDevice * dev)156 pipe_new(uint64_t channel, PipeDevice* dev)
157 {
158     Pipe*  pipe = pipe_new0(dev);
159     pipe->channel = channel;
160     pipe->opaque  = pipeConnector_new(pipe);
161     return pipe;
162 }
163 
164 static Pipe**
pipe_list_findp_channel(Pipe ** list,uint64_t channel)165 pipe_list_findp_channel( Pipe** list, uint64_t channel )
166 {
167     Pipe** pnode = list;
168     for (;;) {
169         Pipe* node = *pnode;
170         if (node == NULL || node->channel == channel) {
171             break;
172         }
173         pnode = &node->next;
174     }
175     return pnode;
176 }
177 
178 #if 0
179 static Pipe**
180 pipe_list_findp_opaque( Pipe** list, void* opaque )
181 {
182     Pipe** pnode = list;
183     for (;;) {
184         Pipe* node = *pnode;
185         if (node == NULL || node->opaque == opaque) {
186             break;
187         }
188         pnode = &node->next;
189     }
190     return pnode;
191 }
192 #endif
193 
194 static Pipe**
pipe_list_findp_waked(Pipe ** list,Pipe * pipe)195 pipe_list_findp_waked( Pipe** list, Pipe* pipe )
196 {
197     Pipe** pnode = list;
198     for (;;) {
199         Pipe* node = *pnode;
200         if (node == NULL || node == pipe) {
201             break;
202         }
203         pnode = &node->next_waked;
204     }
205     return pnode;
206 }
207 
208 
209 static void
pipe_list_remove_waked(Pipe ** list,Pipe * pipe)210 pipe_list_remove_waked( Pipe** list, Pipe*  pipe )
211 {
212     Pipe** lookup = pipe_list_findp_waked(list, pipe);
213     Pipe*  node   = *lookup;
214 
215     if (node != NULL) {
216         (*lookup) = node->next_waked;
217         node->next_waked = NULL;
218     }
219 }
220 
221 static void
pipe_save(Pipe * pipe,QEMUFile * file)222 pipe_save( Pipe* pipe, QEMUFile* file )
223 {
224     if (pipe->service == NULL) {
225         /* pipe->service == NULL means we're still using a PipeConnector */
226         /* Write a zero to indicate this condition */
227         qemu_put_byte(file, 0);
228     } else {
229         /* Otherwise, write a '1' then the service name */
230         qemu_put_byte(file, 1);
231         qemu_put_string(file, pipe->service->name);
232     }
233 
234     /* Now save other common data */
235     qemu_put_be64(file, pipe->channel);
236     qemu_put_byte(file, (int)pipe->wanted);
237     qemu_put_byte(file, (int)pipe->closed);
238 
239     /* Write 1 + args, if any, or simply 0 otherwise */
240     if (pipe->args != NULL) {
241         qemu_put_byte(file, 1);
242         qemu_put_string(file, pipe->args);
243     } else {
244         qemu_put_byte(file, 0);
245     }
246 
247     if (pipe->funcs->save) {
248         pipe->funcs->save(pipe->opaque, file);
249     }
250 }
251 
252 static Pipe*
pipe_load(PipeDevice * dev,QEMUFile * file,int version_id)253 pipe_load( PipeDevice* dev, QEMUFile* file, int version_id )
254 {
255     Pipe*              pipe;
256     const PipeService* service = NULL;
257     int   state = qemu_get_byte(file);
258     uint64_t channel;
259 
260     if (state != 0) {
261         /* Pipe is associated with a service. */
262         char* name = qemu_get_string(file);
263         if (name == NULL)
264             return NULL;
265 
266         service = goldfish_pipe_find_type(name);
267         if (service == NULL) {
268             D("No QEMU pipe service named '%s'", name);
269             AFREE(name);
270             return NULL;
271         }
272     }
273 
274     if (version_id == GOLDFISH_PIPE_SAVE_VERSION_LEGACY) {
275         channel = qemu_get_be32(file);
276     } else {
277         channel = qemu_get_be64(file);
278     }
279     pipe = pipe_new(channel, dev);
280     pipe->wanted  = qemu_get_byte(file);
281     pipe->closed  = qemu_get_byte(file);
282     if (qemu_get_byte(file) != 0) {
283         pipe->args = qemu_get_string(file);
284     }
285 
286     pipe->service = service;
287     if (service != NULL) {
288         pipe->funcs = &service->funcs;
289     }
290 
291     if (pipe->funcs->load) {
292         pipe->opaque = pipe->funcs->load(pipe, service ? service->opaque : NULL, pipe->args, file);
293         if (pipe->opaque == NULL) {
294             AFREE(pipe);
295             return NULL;
296         }
297     } else {
298         /* Force-close the pipe on load */
299         pipe->closed = 1;
300     }
301     return pipe;
302 }
303 
304 static void
pipe_free(Pipe * pipe)305 pipe_free( Pipe* pipe )
306 {
307     /* Call close callback */
308     if (pipe->funcs->close) {
309         pipe->funcs->close(pipe->opaque);
310     }
311     /* Free stuff */
312     AFREE(pipe->args);
313     AFREE(pipe);
314 }
315 
316 /***********************************************************************
317  ***********************************************************************
318  *****
319  *****    P I P E   C O N N E C T O R S
320  *****
321  *****/
322 
323 /* These are used to handle the initial connection attempt, where the
324  * client is going to write the name of the pipe service it wants to
325  * connect to, followed by a terminating zero.
326  */
327 typedef struct {
328     Pipe*  pipe;
329     char   buffer[128];
330     int    buffpos;
331 } PipeConnector;
332 
333 static const GoldfishPipeFuncs  pipeConnector_funcs;  // forward
334 
335 void*
pipeConnector_new(Pipe * pipe)336 pipeConnector_new(Pipe*  pipe)
337 {
338     PipeConnector*  pcon;
339 
340     ANEW0(pcon);
341     pcon->pipe  = pipe;
342     pipe->funcs = &pipeConnector_funcs;
343     return pcon;
344 }
345 
346 static void
pipeConnector_close(void * opaque)347 pipeConnector_close( void* opaque )
348 {
349     PipeConnector*  pcon = opaque;
350     AFREE(pcon);
351 }
352 
353 static int
pipeConnector_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)354 pipeConnector_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
355 {
356     PipeConnector* pcon = opaque;
357     const GoldfishPipeBuffer*  buffers_limit = buffers + numBuffers;
358     int ret = 0;
359 
360     DD("%s: channel=0x%llx numBuffers=%d", __FUNCTION__,
361        (unsigned long long)pcon->pipe->channel,
362        numBuffers);
363 
364     while (buffers < buffers_limit) {
365         int  avail;
366 
367         DD("%s: buffer data (%3d bytes): '%.*s'", __FUNCTION__,
368            buffers[0].size, buffers[0].size, buffers[0].data);
369 
370         if (buffers[0].size == 0) {
371             buffers++;
372             continue;
373         }
374 
375         avail = sizeof(pcon->buffer) - pcon->buffpos;
376         if (avail > buffers[0].size)
377             avail = buffers[0].size;
378 
379         if (avail > 0) {
380             memcpy(pcon->buffer + pcon->buffpos, buffers[0].data, avail);
381             pcon->buffpos += avail;
382             ret += avail;
383         }
384         buffers++;
385     }
386 
387     /* Now check that our buffer contains a zero-terminated string */
388     if (memchr(pcon->buffer, '\0', pcon->buffpos) != NULL) {
389         /* Acceptable formats for the connection string are:
390          *
391          *   pipe:<name>
392          *   pipe:<name>:<arguments>
393          */
394         char* pipeName;
395         char* pipeArgs;
396 
397         D("%s: connector: '%s'", __FUNCTION__, pcon->buffer);
398 
399         if (memcmp(pcon->buffer, "pipe:", 5) != 0) {
400             /* Nope, we don't handle these for now. */
401             D("%s: Unknown pipe connection: '%s'", __FUNCTION__, pcon->buffer);
402             return PIPE_ERROR_INVAL;
403         }
404 
405         pipeName = pcon->buffer + 5;
406         pipeArgs = strchr(pipeName, ':');
407 
408         if (pipeArgs != NULL) {
409             *pipeArgs++ = '\0';
410             if (!*pipeArgs)
411                 pipeArgs = NULL;
412         }
413 
414         Pipe* pipe = pcon->pipe;
415         const PipeService* svc = goldfish_pipe_find_type(pipeName);
416         if (svc == NULL) {
417             D("%s: Unknown server!", __FUNCTION__);
418             return PIPE_ERROR_INVAL;
419         }
420 
421         void*  peer = svc->funcs.init(pipe, svc->opaque, pipeArgs);
422         if (peer == NULL) {
423             D("%s: Initialization failed!", __FUNCTION__);
424             return PIPE_ERROR_INVAL;
425         }
426 
427         /* Do the evil switch now */
428         pipe->opaque = peer;
429         pipe->service = svc;
430         pipe->funcs  = &svc->funcs;
431         pipe->args   = ASTRDUP(pipeArgs);
432         AFREE(pcon);
433     }
434 
435     return ret;
436 }
437 
438 static int
pipeConnector_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)439 pipeConnector_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
440 {
441     return PIPE_ERROR_IO;
442 }
443 
444 static unsigned
pipeConnector_poll(void * opaque)445 pipeConnector_poll( void* opaque )
446 {
447     return PIPE_POLL_OUT;
448 }
449 
450 static void
pipeConnector_wakeOn(void * opaque,int flags)451 pipeConnector_wakeOn( void* opaque, int flags )
452 {
453     /* nothing, really should never happen */
454 }
455 
456 static void
pipeConnector_save(void * pipe,QEMUFile * file)457 pipeConnector_save( void* pipe, QEMUFile* file )
458 {
459     PipeConnector*  pcon = pipe;
460     qemu_put_sbe32(file, pcon->buffpos);
461     qemu_put_sbuffer(file, (const int8_t*)pcon->buffer, pcon->buffpos);
462 }
463 
464 static void*
pipeConnector_load(void * hwpipe,void * pipeOpaque,const char * args,QEMUFile * file)465 pipeConnector_load( void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* file )
466 {
467     PipeConnector*  pcon;
468 
469     int len = qemu_get_sbe32(file);
470     if (len < 0 || len > sizeof(pcon->buffer)) {
471         return NULL;
472     }
473     pcon = pipeConnector_new(hwpipe);
474     pcon->buffpos = len;
475     if (qemu_get_buffer(file, (uint8_t*)pcon->buffer, pcon->buffpos) != pcon->buffpos) {
476         AFREE(pcon);
477         return NULL;
478     }
479     return pcon;
480 }
481 
482 static const GoldfishPipeFuncs  pipeConnector_funcs = {
483     NULL,  /* init */
484     pipeConnector_close,        /* should rarely happen */
485     pipeConnector_sendBuffers,  /* the interesting stuff */
486     pipeConnector_recvBuffers,  /* should not happen */
487     pipeConnector_poll,         /* should not happen */
488     pipeConnector_wakeOn,       /* should not happen */
489     pipeConnector_save,
490     pipeConnector_load,
491 };
492 
493 /***********************************************************************
494  ***********************************************************************
495  *****
496  *****    Z E R O   P I P E S
497  *****
498  *****/
499 
500 /* A simple pipe service that mimics /dev/zero, you can write anything to
501  * it, and you can always read any number of zeros from it. Useful for debugging
502  * the kernel driver.
503  */
504 #if DEBUG_ZERO_PIPE
505 
506 typedef struct {
507     void* hwpipe;
508 } ZeroPipe;
509 
510 static void*
zeroPipe_init(void * hwpipe,void * svcOpaque,const char * args)511 zeroPipe_init( void* hwpipe, void* svcOpaque, const char* args )
512 {
513     ZeroPipe*  zpipe;
514 
515     D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
516     ANEW0(zpipe);
517     zpipe->hwpipe = hwpipe;
518     return zpipe;
519 }
520 
521 static void
zeroPipe_close(void * opaque)522 zeroPipe_close( void* opaque )
523 {
524     ZeroPipe*  zpipe = opaque;
525 
526     D("%s: hwpipe=%p", __FUNCTION__, zpipe->hwpipe);
527     AFREE(zpipe);
528 }
529 
530 static int
zeroPipe_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)531 zeroPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
532 {
533     int  ret = 0;
534     while (numBuffers > 0) {
535         ret += buffers[0].size;
536         buffers++;
537         numBuffers--;
538     }
539     return ret;
540 }
541 
542 static int
zeroPipe_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)543 zeroPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
544 {
545     int  ret = 0;
546     while (numBuffers > 0) {
547         ret += buffers[0].size;
548         memset(buffers[0].data, 0, buffers[0].size);
549         buffers++;
550         numBuffers--;
551     }
552     return ret;
553 }
554 
555 static unsigned
zeroPipe_poll(void * opaque)556 zeroPipe_poll( void* opaque )
557 {
558     return PIPE_POLL_IN | PIPE_POLL_OUT;
559 }
560 
561 static void
zeroPipe_wakeOn(void * opaque,int flags)562 zeroPipe_wakeOn( void* opaque, int flags )
563 {
564     /* nothing to do here */
565 }
566 
567 static const GoldfishPipeFuncs  zeroPipe_funcs = {
568     zeroPipe_init,
569     zeroPipe_close,
570     zeroPipe_sendBuffers,
571     zeroPipe_recvBuffers,
572     zeroPipe_poll,
573     zeroPipe_wakeOn,
574 };
575 
576 #endif /* DEBUG_ZERO */
577 
578 /***********************************************************************
579  ***********************************************************************
580  *****
581  *****    P I N G   P O N G   P I P E S
582  *****
583  *****/
584 
585 /* Similar debug service that sends back anything it receives */
586 /* All data is kept in a circular dynamic buffer */
587 
588 #if DEBUG_PINGPONG_PIPE
589 
590 /* Initial buffer size */
591 #define PINGPONG_SIZE  1024
592 
593 typedef struct {
594     void*     hwpipe;
595     uint8_t*  buffer;
596     size_t    size;
597     size_t    pos;
598     size_t    count;
599     unsigned  flags;
600 } PingPongPipe;
601 
602 static void
pingPongPipe_init0(PingPongPipe * pipe,void * hwpipe,void * svcOpaque)603 pingPongPipe_init0( PingPongPipe* pipe, void* hwpipe, void* svcOpaque )
604 {
605     pipe->hwpipe = hwpipe;
606     pipe->size = PINGPONG_SIZE;
607     pipe->buffer = malloc(pipe->size);
608     pipe->pos = 0;
609     pipe->count = 0;
610 }
611 
612 static void*
pingPongPipe_init(void * hwpipe,void * svcOpaque,const char * args)613 pingPongPipe_init( void* hwpipe, void* svcOpaque, const char* args )
614 {
615     PingPongPipe*  ppipe;
616 
617     D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
618     ANEW0(ppipe);
619     pingPongPipe_init0(ppipe, hwpipe, svcOpaque);
620     return ppipe;
621 }
622 
623 static void
pingPongPipe_close(void * opaque)624 pingPongPipe_close( void* opaque )
625 {
626     PingPongPipe*  ppipe = opaque;
627 
628     D("%s: hwpipe=%p (pos=%d count=%d size=%d)", __FUNCTION__,
629       ppipe->hwpipe, ppipe->pos, ppipe->count, ppipe->size);
630     free(ppipe->buffer);
631     AFREE(ppipe);
632 }
633 
634 static int
pingPongPipe_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)635 pingPongPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
636 {
637     PingPongPipe*  pipe = opaque;
638     int  ret = 0;
639     int  count;
640     const GoldfishPipeBuffer* buff = buffers;
641     const GoldfishPipeBuffer* buffEnd = buff + numBuffers;
642 
643     count = 0;
644     for ( ; buff < buffEnd; buff++ )
645         count += buff->size;
646 
647     /* Do we need to grow the pingpong buffer? */
648     while (count > pipe->size - pipe->count) {
649         size_t    newsize = pipe->size*2;
650         uint8_t*  newbuff = realloc(pipe->buffer, newsize);
651         int       wpos    = pipe->pos + pipe->count;
652         if (newbuff == NULL) {
653             break;
654         }
655         if (wpos > pipe->size) {
656             wpos -= pipe->size;
657             memcpy(newbuff + pipe->size, newbuff, wpos);
658         }
659         pipe->buffer = newbuff;
660         pipe->size   = newsize;
661         D("pingpong buffer is now %d bytes", newsize);
662     }
663 
664     for ( buff = buffers; buff < buffEnd; buff++ ) {
665         int avail = pipe->size - pipe->count;
666         if (avail <= 0) {
667             if (ret == 0)
668                 ret = PIPE_ERROR_AGAIN;
669             break;
670         }
671         if (avail > buff->size) {
672             avail = buff->size;
673         }
674 
675         int wpos = pipe->pos + pipe->count;
676         if (wpos >= pipe->size) {
677             wpos -= pipe->size;
678         }
679         if (wpos + avail <= pipe->size) {
680             memcpy(pipe->buffer + wpos, buff->data, avail);
681         } else {
682             int  avail2 = pipe->size - wpos;
683             memcpy(pipe->buffer + wpos, buff->data, avail2);
684             memcpy(pipe->buffer, buff->data + avail2, avail - avail2);
685         }
686         pipe->count += avail;
687         ret += avail;
688     }
689 
690     /* Wake up any waiting readers if we wrote something */
691     if (pipe->count > 0 && (pipe->flags & PIPE_WAKE_READ)) {
692         goldfish_pipe_wake(pipe->hwpipe, PIPE_WAKE_READ);
693     }
694 
695     return ret;
696 }
697 
698 static int
pingPongPipe_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)699 pingPongPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
700 {
701     PingPongPipe*  pipe = opaque;
702     int  ret = 0;
703 
704     while (numBuffers > 0) {
705         int avail = pipe->count;
706         if (avail <= 0) {
707             if (ret == 0)
708                 ret = PIPE_ERROR_AGAIN;
709             break;
710         }
711         if (avail > buffers[0].size) {
712             avail = buffers[0].size;
713         }
714 
715         int rpos = pipe->pos;
716 
717         if (rpos + avail <= pipe->size) {
718             memcpy(buffers[0].data, pipe->buffer + rpos, avail);
719         } else {
720             int  avail2 = pipe->size - rpos;
721             memcpy(buffers[0].data, pipe->buffer + rpos, avail2);
722             memcpy(buffers[0].data + avail2, pipe->buffer, avail - avail2);
723         }
724         pipe->count -= avail;
725         pipe->pos   += avail;
726         if (pipe->pos >= pipe->size) {
727             pipe->pos -= pipe->size;
728         }
729         ret += avail;
730         numBuffers--;
731         buffers++;
732     }
733 
734     /* Wake up any waiting readers if we wrote something */
735     if (pipe->count < PINGPONG_SIZE && (pipe->flags & PIPE_WAKE_WRITE)) {
736         goldfish_pipe_wake(pipe->hwpipe, PIPE_WAKE_WRITE);
737     }
738 
739     return ret;
740 }
741 
742 static unsigned
pingPongPipe_poll(void * opaque)743 pingPongPipe_poll( void* opaque )
744 {
745     PingPongPipe*  pipe = opaque;
746     unsigned       ret = 0;
747 
748     if (pipe->count < pipe->size)
749         ret |= PIPE_POLL_OUT;
750 
751     if (pipe->count > 0)
752         ret |= PIPE_POLL_IN;
753 
754     return ret;
755 }
756 
757 static void
pingPongPipe_wakeOn(void * opaque,int flags)758 pingPongPipe_wakeOn( void* opaque, int flags )
759 {
760     PingPongPipe* pipe = opaque;
761     pipe->flags |= (unsigned)flags;
762 }
763 
764 static const GoldfishPipeFuncs  pingPongPipe_funcs = {
765     pingPongPipe_init,
766     pingPongPipe_close,
767     pingPongPipe_sendBuffers,
768     pingPongPipe_recvBuffers,
769     pingPongPipe_poll,
770     pingPongPipe_wakeOn,
771 };
772 
773 #endif /* DEBUG_PINGPONG_PIPE */
774 
775 /***********************************************************************
776  ***********************************************************************
777  *****
778  *****    T H R O T T L E   P I P E S
779  *****
780  *****/
781 
782 /* Similar to PingPongPipe, but will throttle the bandwidth to test
783  * blocking I/O.
784  */
785 
786 #ifdef DEBUG_THROTTLE_PIPE
787 
788 typedef struct {
789     PingPongPipe  pingpong;
790     double        sendRate;
791     int64_t       sendExpiration;
792     double        recvRate;
793     int64_t       recvExpiration;
794     QEMUTimer*    timer;
795 } ThrottlePipe;
796 
797 /* forward declaration */
798 static void throttlePipe_timerFunc( void* opaque );
799 
800 static void*
throttlePipe_init(void * hwpipe,void * svcOpaque,const char * args)801 throttlePipe_init( void* hwpipe, void* svcOpaque, const char* args )
802 {
803     ThrottlePipe* pipe;
804 
805     ANEW0(pipe);
806     pingPongPipe_init0(&pipe->pingpong, hwpipe, svcOpaque);
807     pipe->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, throttlePipe_timerFunc, pipe);
808     /* For now, limit to 500 KB/s in both directions */
809     pipe->sendRate = 1e9 / (500*1024*8);
810     pipe->recvRate = pipe->sendRate;
811     return pipe;
812 }
813 
814 static void
throttlePipe_close(void * opaque)815 throttlePipe_close( void* opaque )
816 {
817     ThrottlePipe* pipe = opaque;
818 
819     timer_del(pipe->timer);
820     timer_free(pipe->timer);
821     pingPongPipe_close(&pipe->pingpong);
822 }
823 
824 static void
throttlePipe_rearm(ThrottlePipe * pipe)825 throttlePipe_rearm( ThrottlePipe* pipe )
826 {
827     int64_t  minExpiration = 0;
828 
829     DD("%s: sendExpiration=%lld recvExpiration=%lld\n", __FUNCTION__, pipe->sendExpiration, pipe->recvExpiration);
830 
831     if (pipe->sendExpiration) {
832         if (minExpiration == 0 || pipe->sendExpiration < minExpiration)
833             minExpiration = pipe->sendExpiration;
834     }
835 
836     if (pipe->recvExpiration) {
837         if (minExpiration == 0 || pipe->recvExpiration < minExpiration)
838             minExpiration = pipe->recvExpiration;
839     }
840 
841     if (minExpiration != 0) {
842         DD("%s: Arming for %lld\n", __FUNCTION__, minExpiration);
843         timer_mod(pipe->timer, minExpiration);
844     }
845 }
846 
847 static void
throttlePipe_timerFunc(void * opaque)848 throttlePipe_timerFunc( void* opaque )
849 {
850     ThrottlePipe* pipe = opaque;
851     int64_t  now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
852 
853     DD("%s: TICK! now=%lld sendExpiration=%lld recvExpiration=%lld\n",
854        __FUNCTION__, now, pipe->sendExpiration, pipe->recvExpiration);
855 
856     /* Timer has expired, signal wake up if needed */
857     int      flags = 0;
858 
859     if (pipe->sendExpiration && now > pipe->sendExpiration) {
860         flags |= PIPE_WAKE_WRITE;
861         pipe->sendExpiration = 0;
862     }
863     if (pipe->recvExpiration && now > pipe->recvExpiration) {
864         flags |= PIPE_WAKE_READ;
865         pipe->recvExpiration = 0;
866     }
867     flags &= pipe->pingpong.flags;
868     if (flags != 0) {
869         DD("%s: WAKE %d\n", __FUNCTION__, flags);
870         goldfish_pipe_wake(pipe->pingpong.hwpipe, flags);
871     }
872 
873     throttlePipe_rearm(pipe);
874 }
875 
876 static int
throttlePipe_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)877 throttlePipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
878 {
879     ThrottlePipe*  pipe = opaque;
880     int            ret;
881 
882     if (pipe->sendExpiration > 0) {
883         return PIPE_ERROR_AGAIN;
884     }
885 
886     ret = pingPongPipe_sendBuffers(&pipe->pingpong, buffers, numBuffers);
887     if (ret > 0) {
888         /* Compute next send expiration time */
889         pipe->sendExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->sendRate;
890         throttlePipe_rearm(pipe);
891     }
892     return ret;
893 }
894 
895 static int
throttlePipe_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)896 throttlePipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
897 {
898     ThrottlePipe* pipe = opaque;
899     int           ret;
900 
901     if (pipe->recvExpiration > 0) {
902         return PIPE_ERROR_AGAIN;
903     }
904 
905     ret = pingPongPipe_recvBuffers(&pipe->pingpong, buffers, numBuffers);
906     if (ret > 0) {
907         pipe->recvExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->recvRate;
908         throttlePipe_rearm(pipe);
909     }
910     return ret;
911 }
912 
913 static unsigned
throttlePipe_poll(void * opaque)914 throttlePipe_poll( void* opaque )
915 {
916     ThrottlePipe*  pipe = opaque;
917     unsigned       ret  = pingPongPipe_poll(&pipe->pingpong);
918 
919     if (pipe->sendExpiration > 0)
920         ret &= ~PIPE_POLL_OUT;
921 
922     if (pipe->recvExpiration > 0)
923         ret &= ~PIPE_POLL_IN;
924 
925     return ret;
926 }
927 
928 static void
throttlePipe_wakeOn(void * opaque,int flags)929 throttlePipe_wakeOn( void* opaque, int flags )
930 {
931     ThrottlePipe* pipe = opaque;
932     pingPongPipe_wakeOn(&pipe->pingpong, flags);
933 }
934 
935 static const GoldfishPipeFuncs  throttlePipe_funcs = {
936     throttlePipe_init,
937     throttlePipe_close,
938     throttlePipe_sendBuffers,
939     throttlePipe_recvBuffers,
940     throttlePipe_poll,
941     throttlePipe_wakeOn,
942 };
943 
944 #endif /* DEBUG_THROTTLE_PIPE */
945 
946 /***********************************************************************
947  ***********************************************************************
948  *****
949  *****    G O L D F I S H   P I P E   D E V I C E
950  *****
951  *****/
952 
953 struct PipeDevice {
954     struct goldfish_device dev;
955 
956     /* the list of all pipes */
957     Pipe*  pipes;
958 
959     /* the list of signalled pipes */
960     Pipe*  signaled_pipes;
961 
962     /* i/o registers */
963     uint64_t  address;
964     uint32_t  size;
965     uint32_t  status;
966     uint64_t  channel;
967     uint32_t  wakes;
968     uint64_t  params_addr;
969 };
970 
971 static void
pipeDevice_doCommand(PipeDevice * dev,uint32_t command)972 pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
973 {
974     Pipe** lookup = pipe_list_findp_channel(&dev->pipes, dev->channel);
975     Pipe*  pipe   = *lookup;
976     CPUOldState* env = cpu_single_env;
977 
978     /* Check that we're referring a known pipe channel */
979     if (command != PIPE_CMD_OPEN && pipe == NULL) {
980         dev->status = PIPE_ERROR_INVAL;
981         return;
982     }
983 
984     /* If the pipe is closed by the host, return an error */
985     if (pipe != NULL && pipe->closed && command != PIPE_CMD_CLOSE) {
986         dev->status = PIPE_ERROR_IO;
987         return;
988     }
989 
990     switch (command) {
991     case PIPE_CMD_OPEN:
992         DD("%s: CMD_OPEN channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
993         if (pipe != NULL) {
994             dev->status = PIPE_ERROR_INVAL;
995             break;
996         }
997         pipe = pipe_new(dev->channel, dev);
998         pipe->next = dev->pipes;
999         dev->pipes = pipe;
1000         dev->status = 0;
1001         break;
1002 
1003     case PIPE_CMD_CLOSE:
1004         DD("%s: CMD_CLOSE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
1005         /* Remove from device's lists */
1006         *lookup = pipe->next;
1007         pipe->next = NULL;
1008         pipe_list_remove_waked(&dev->signaled_pipes, pipe);
1009         pipe_free(pipe);
1010         break;
1011 
1012     case PIPE_CMD_POLL:
1013         dev->status = pipe->funcs->poll(pipe->opaque);
1014         DD("%s: CMD_POLL > status=%d", __FUNCTION__, dev->status);
1015         break;
1016 
1017     case PIPE_CMD_READ_BUFFER: {
1018         /* Translate virtual address into physical one, into emulator memory. */
1019         GoldfishPipeBuffer  buffer;
1020         target_ulong        address = dev->address;
1021         target_ulong        page    = address & TARGET_PAGE_MASK;
1022         hwaddr  phys;
1023         phys = safe_get_phys_page_debug(ENV_GET_CPU(env), page);
1024 #ifdef TARGET_X86_64
1025         phys = phys & TARGET_PTE_MASK;
1026 #endif
1027         buffer.data = qemu_get_ram_ptr(phys) + (address - page);
1028         buffer.size = dev->size;
1029         dev->status = pipe->funcs->recvBuffers(pipe->opaque, &buffer, 1);
1030         DD("%s: CMD_READ_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
1031            __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
1032            dev->size, dev->status);
1033         break;
1034     }
1035 
1036     case PIPE_CMD_WRITE_BUFFER: {
1037         /* Translate virtual address into physical one, into emulator memory. */
1038         GoldfishPipeBuffer  buffer;
1039         target_ulong        address = dev->address;
1040         target_ulong        page    = address & TARGET_PAGE_MASK;
1041         hwaddr  phys;
1042         phys = safe_get_phys_page_debug(ENV_GET_CPU(env), page);
1043 #ifdef TARGET_X86_64
1044         phys = phys & TARGET_PTE_MASK;
1045 #endif
1046         buffer.data = qemu_get_ram_ptr(phys) + (address - page);
1047         buffer.size = dev->size;
1048         dev->status = pipe->funcs->sendBuffers(pipe->opaque, &buffer, 1);
1049         DD("%s: CMD_WRITE_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
1050            __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
1051            dev->size, dev->status);
1052         break;
1053     }
1054 
1055     case PIPE_CMD_WAKE_ON_READ:
1056         DD("%s: CMD_WAKE_ON_READ channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
1057         if ((pipe->wanted & PIPE_WAKE_READ) == 0) {
1058             pipe->wanted |= PIPE_WAKE_READ;
1059             pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
1060         }
1061         dev->status = 0;
1062         break;
1063 
1064     case PIPE_CMD_WAKE_ON_WRITE:
1065         DD("%s: CMD_WAKE_ON_WRITE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
1066         if ((pipe->wanted & PIPE_WAKE_WRITE) == 0) {
1067             pipe->wanted |= PIPE_WAKE_WRITE;
1068             pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
1069         }
1070         dev->status = 0;
1071         break;
1072 
1073     default:
1074         D("%s: command=%d (0x%x)\n", __FUNCTION__, command, command);
1075     }
1076 }
1077 
pipe_dev_write(void * opaque,hwaddr offset,uint32_t value)1078 static void pipe_dev_write(void *opaque, hwaddr offset, uint32_t value)
1079 {
1080     PipeDevice *s = (PipeDevice *)opaque;
1081 
1082     switch (offset) {
1083     case PIPE_REG_COMMAND:
1084         DR("%s: command=%d (0x%x)", __FUNCTION__, value, value);
1085         pipeDevice_doCommand(s, value);
1086         break;
1087 
1088     case PIPE_REG_SIZE:
1089         DR("%s: size=%d (0x%x)", __FUNCTION__, value, value);
1090         s->size = value;
1091         break;
1092 
1093     case PIPE_REG_ADDRESS:
1094         DR("%s: address=%d (0x%x)", __FUNCTION__, value, value);
1095         uint64_set_low(&s->address, value);
1096         break;
1097 
1098     case PIPE_REG_ADDRESS_HIGH:
1099         DR("%s: address_high=%d (0x%x)", __FUNCTION__, value, value);
1100         uint64_set_high(&s->address, value);
1101         break;
1102 
1103     case PIPE_REG_CHANNEL:
1104         DR("%s: channel=%d (0x%x)", __FUNCTION__, value, value);
1105         uint64_set_low(&s->channel, value);
1106         break;
1107 
1108     case PIPE_REG_CHANNEL_HIGH:
1109         DR("%s: channel_high=%d (0x%x)", __FUNCTION__, value, value);
1110         uint64_set_high(&s->channel, value);
1111         break;
1112 
1113     case PIPE_REG_PARAMS_ADDR_HIGH:
1114         s->params_addr = (s->params_addr & ~(0xFFFFFFFFULL << 32) ) |
1115                           ((uint64_t)value << 32);
1116         break;
1117 
1118     case PIPE_REG_PARAMS_ADDR_LOW:
1119         s->params_addr = (s->params_addr & ~(0xFFFFFFFFULL) ) | value;
1120         break;
1121 
1122     case PIPE_REG_ACCESS_PARAMS:
1123     {
1124         struct access_params aps;
1125         struct access_params_64 aps64;
1126         uint32_t cmd;
1127 
1128         /* Don't touch aps.result if anything wrong */
1129         if (s->params_addr == 0)
1130             break;
1131 
1132         if (goldfish_guest_is_64bit()) {
1133             cpu_physical_memory_read(s->params_addr, (void*)&aps64,
1134                                      sizeof(aps64));
1135         } else {
1136             cpu_physical_memory_read(s->params_addr, (void*)&aps,
1137                                      sizeof(aps));
1138         }
1139         /* sync pipe device state from batch buffer */
1140         if (goldfish_guest_is_64bit()) {
1141             s->channel = aps64.channel;
1142             s->size = aps64.size;
1143             s->address = aps64.address;
1144             cmd = aps64.cmd;
1145         } else {
1146             s->channel = aps.channel;
1147             s->size = aps.size;
1148             s->address = aps.address;
1149             cmd = aps.cmd;
1150         }
1151         if ((cmd != PIPE_CMD_READ_BUFFER) && (cmd != PIPE_CMD_WRITE_BUFFER))
1152             break;
1153 
1154         pipeDevice_doCommand(s, cmd);
1155         if (goldfish_guest_is_64bit()) {
1156             aps64.result = s->status;
1157             cpu_physical_memory_write(s->params_addr, (void*)&aps64,
1158                                       sizeof(aps64));
1159         } else {
1160             aps.result = s->status;
1161             cpu_physical_memory_write(s->params_addr, (void*)&aps,
1162                                       sizeof(aps));
1163         }
1164     }
1165     break;
1166 
1167     default:
1168         D("%s: offset=%d (0x%x) value=%d (0x%x)\n", __FUNCTION__, offset,
1169             offset, value, value);
1170         break;
1171     }
1172 }
1173 
1174 /* I/O read */
pipe_dev_read(void * opaque,hwaddr offset)1175 static uint32_t pipe_dev_read(void *opaque, hwaddr offset)
1176 {
1177     PipeDevice *dev = (PipeDevice *)opaque;
1178 
1179     switch (offset) {
1180     case PIPE_REG_STATUS:
1181         DR("%s: REG_STATUS status=%d (0x%x)", __FUNCTION__, dev->status, dev->status);
1182         return dev->status;
1183 
1184     case PIPE_REG_CHANNEL:
1185         if (dev->signaled_pipes != NULL) {
1186             Pipe* pipe = dev->signaled_pipes;
1187             DR("%s: channel=0x%llx wanted=%d", __FUNCTION__,
1188                (unsigned long long)pipe->channel, pipe->wanted);
1189             dev->wakes = pipe->wanted;
1190             pipe->wanted = 0;
1191             dev->signaled_pipes = pipe->next_waked;
1192             pipe->next_waked = NULL;
1193             if (dev->signaled_pipes == NULL) {
1194                 goldfish_device_set_irq(&dev->dev, 0, 0);
1195                 DD("%s: lowering IRQ", __FUNCTION__);
1196             }
1197             return (uint32_t)(pipe->channel & 0xFFFFFFFFUL);
1198         }
1199         DR("%s: no signaled channels", __FUNCTION__);
1200         return 0;
1201 
1202     case PIPE_REG_CHANNEL_HIGH:
1203         if (dev->signaled_pipes != NULL) {
1204             Pipe* pipe = dev->signaled_pipes;
1205             DR("%s: channel_high=0x%llx wanted=%d", __FUNCTION__,
1206                (unsigned long long)pipe->channel, pipe->wanted);
1207             return (uint32_t)(pipe->channel >> 32);
1208         }
1209         DR("%s: no signaled channels", __FUNCTION__);
1210         return 0;
1211 
1212     case PIPE_REG_WAKES:
1213         DR("%s: wakes %d", __FUNCTION__, dev->wakes);
1214         return dev->wakes;
1215 
1216     case PIPE_REG_PARAMS_ADDR_HIGH:
1217         return (uint32_t)(dev->params_addr >> 32);
1218 
1219     case PIPE_REG_PARAMS_ADDR_LOW:
1220         return (uint32_t)(dev->params_addr & 0xFFFFFFFFUL);
1221 
1222     default:
1223         D("%s: offset=%d (0x%x)\n", __FUNCTION__, offset, offset);
1224     }
1225     return 0;
1226 }
1227 
1228 static CPUReadMemoryFunc *pipe_dev_readfn[] = {
1229    pipe_dev_read,
1230    pipe_dev_read,
1231    pipe_dev_read
1232 };
1233 
1234 static CPUWriteMemoryFunc *pipe_dev_writefn[] = {
1235    pipe_dev_write,
1236    pipe_dev_write,
1237    pipe_dev_write
1238 };
1239 
1240 static void
goldfish_pipe_save(QEMUFile * file,void * opaque)1241 goldfish_pipe_save( QEMUFile* file, void* opaque )
1242 {
1243     PipeDevice* dev = opaque;
1244     Pipe* pipe;
1245 
1246     qemu_put_be64(file, dev->address);
1247     qemu_put_be32(file, dev->size);
1248     qemu_put_be32(file, dev->status);
1249     qemu_put_be64(file, dev->channel);
1250     qemu_put_be32(file, dev->wakes);
1251     qemu_put_be64(file, dev->params_addr);
1252 
1253     /* Count the number of pipe connections */
1254     int count = 0;
1255     for ( pipe = dev->pipes; pipe; pipe = pipe->next )
1256         count++;
1257 
1258     qemu_put_sbe32(file, count);
1259 
1260     /* Now save each pipe one after the other */
1261     for ( pipe = dev->pipes; pipe; pipe = pipe->next ) {
1262         pipe_save(pipe, file);
1263     }
1264 }
1265 
1266 static int
goldfish_pipe_load(QEMUFile * file,void * opaque,int version_id)1267 goldfish_pipe_load( QEMUFile* file, void* opaque, int version_id )
1268 {
1269     PipeDevice* dev = opaque;
1270     Pipe*       pipe;
1271 
1272     if ((version_id != GOLDFISH_PIPE_SAVE_VERSION) &&
1273         (version_id != GOLDFISH_PIPE_SAVE_VERSION_LEGACY)) {
1274         return -EINVAL;
1275     }
1276     if (version_id == GOLDFISH_PIPE_SAVE_VERSION_LEGACY) {
1277         dev->address = (uint64_t)qemu_get_be32(file);
1278     } else {
1279         dev->address = qemu_get_be64(file);
1280     }
1281     dev->size    = qemu_get_be32(file);
1282     dev->status  = qemu_get_be32(file);
1283     if (version_id == GOLDFISH_PIPE_SAVE_VERSION_LEGACY) {
1284         dev->channel = (uint64_t)qemu_get_be32(file);
1285     } else {
1286         dev->channel = qemu_get_be64(file);
1287     }
1288     dev->wakes   = qemu_get_be32(file);
1289     dev->params_addr   = qemu_get_be64(file);
1290 
1291     /* Count the number of pipe connections */
1292     int count = qemu_get_sbe32(file);
1293 
1294     /* Load all pipe connections */
1295     for ( ; count > 0; count-- ) {
1296         pipe = pipe_load(dev, file, version_id);
1297         if (pipe == NULL) {
1298             return -EIO;
1299         }
1300         pipe->next = dev->pipes;
1301         dev->pipes = pipe;
1302     }
1303 
1304     /* Now we need to wake/close all relevant pipes */
1305     for ( pipe = dev->pipes; pipe; pipe = pipe->next ) {
1306         if (pipe->wanted != 0)
1307             goldfish_pipe_wake(pipe, pipe->wanted);
1308         if (pipe->closed != 0)
1309             goldfish_pipe_close(pipe);
1310     }
1311     return 0;
1312 }
1313 
1314 /* initialize the trace device */
pipe_dev_init(bool newDeviceNaming)1315 void pipe_dev_init(bool newDeviceNaming)
1316 {
1317     PipeDevice *s;
1318 
1319     s = (PipeDevice *) g_malloc0(sizeof(*s));
1320 
1321     s->dev.name = newDeviceNaming ? "goldfish_pipe" : "qemu_pipe";
1322     s->dev.id = -1;
1323     s->dev.base = 0;       // will be allocated dynamically
1324     s->dev.size = 0x2000;
1325     s->dev.irq = 0;
1326     s->dev.irq_count = 1;
1327 
1328     goldfish_device_add(&s->dev, pipe_dev_readfn, pipe_dev_writefn, s);
1329 
1330     register_savevm(NULL,
1331                     "goldfish_pipe",
1332                     0,
1333                     GOLDFISH_PIPE_SAVE_VERSION,
1334                     goldfish_pipe_save,
1335                     goldfish_pipe_load,
1336                     s);
1337 
1338 #if DEBUG_ZERO_PIPE
1339     goldfish_pipe_add_type("zero", NULL, &zeroPipe_funcs);
1340 #endif
1341 #if DEBUG_PINGPONG_PIPE
1342     goldfish_pipe_add_type("pingpong", NULL, &pingPongPipe_funcs);
1343 #endif
1344 #if DEBUG_THROTTLE_PIPE
1345     goldfish_pipe_add_type("throttle", NULL, &throttlePipe_funcs);
1346 #endif
1347 }
1348 
1349 void
goldfish_pipe_wake(void * hwpipe,unsigned flags)1350 goldfish_pipe_wake( void* hwpipe, unsigned flags )
1351 {
1352     Pipe*  pipe = hwpipe;
1353     Pipe** lookup;
1354     PipeDevice*  dev = pipe->device;
1355 
1356     DD("%s: channel=0x%llx flags=%d", __FUNCTION__, (unsigned long long)pipe->channel, flags);
1357 
1358     /* If not already there, add to the list of signaled pipes */
1359     lookup = pipe_list_findp_waked(&dev->signaled_pipes, pipe);
1360     if (!*lookup) {
1361         pipe->next_waked = dev->signaled_pipes;
1362         dev->signaled_pipes = pipe;
1363     }
1364     pipe->wanted |= (unsigned)flags;
1365 
1366     /* Raise IRQ to indicate there are items on our list ! */
1367     goldfish_device_set_irq(&dev->dev, 0, 1);
1368     DD("%s: raising IRQ", __FUNCTION__);
1369 }
1370 
1371 void
goldfish_pipe_close(void * hwpipe)1372 goldfish_pipe_close( void* hwpipe )
1373 {
1374     Pipe* pipe = hwpipe;
1375 
1376     D("%s: channel=0x%llx (closed=%d)", __FUNCTION__, (unsigned long long)pipe->channel, pipe->closed);
1377 
1378     if (!pipe->closed) {
1379         pipe->closed = 1;
1380         goldfish_pipe_wake( hwpipe, PIPE_WAKE_CLOSED );
1381     }
1382 }
1383