android_pipe: import the qemu_pipe/goldfish_pipe code

This brings in the android emulator pipe code from the current aosp-qemu
master branch. It works with and has been tested with the pingpong
pipe device. Currently the device cannot save and restore.

  - remove dependency on android utils (ANEW/ASTRDUP/AFREE)
  - detach from the goldfish_device bus bits (inc irq raising)
  - import a few helper functions (uint64_set_high/low, goldfish_guest_is_64bit)
  - disable the VM save/restore code
  - use current_cpu for memory translation ops instead of cpu_single_env
  - fix debugging prints using portable formats
  - common code path for translating vaddr->qemu addr*
  - make some debug statments user-visible (unimp and guest errors)

There is a hacking backlink between AndroidPipeState and the PipeDevice
stuff (which should be merged cleanly later) just so we can get back to
->irq when we need to.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
[cdall: special casing "qemud:<name>"]
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index b1dc85f..f10cc69 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -89,3 +89,5 @@
 CONFIG_ALLWINNER_A10_PIT=y
 CONFIG_ALLWINNER_A10_PIC=y
 CONFIG_ALLWINNER_A10=y
+
+CONFIG_ANDROID_PIPE=y
diff --git a/hw/arm/ranchu.c b/hw/arm/ranchu.c
index f9696a3..be2dbfc 100644
--- a/hw/arm/ranchu.c
+++ b/hw/arm/ranchu.c
@@ -63,6 +63,7 @@
     RANCHU_GF_BATTERY,
     RANCHU_GF_AUDIO,
     RANCHU_GF_EVDEV,
+    RANCHU_ANDROID_PIPE,
     RANCHU_MMIO,
 };
 
@@ -107,6 +108,7 @@
     [RANCHU_GF_AUDIO] = { 0x9030000, 0x100 },
     [RANCHU_GF_EVDEV] = { 0x9040000, 0x1000 },
     [RANCHU_MMIO] = { 0xa000000, 0x200 },
+    [RANCHU_ANDROID_PIPE] = {0xa010000, 0x2000 },
     /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
     /* 0x10000000 .. 0x40000000 reserved for PCI */
     [RANCHU_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
@@ -118,6 +120,7 @@
     [RANCHU_GF_BATTERY] = 3,
     [RANCHU_GF_AUDIO] = 4,
     [RANCHU_GF_EVDEV] = 5,
+    [RANCHU_ANDROID_PIPE] = 6,
     [RANCHU_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
 };
 
@@ -458,6 +461,8 @@
 #endif
     create_simple_device(vbi, pic, RANCHU_GF_EVDEV, "goldfish-events",
                          "generic,goldfish-events-keypad", 1, 0, 0);
+    create_simple_device(vbi, pic, RANCHU_ANDROID_PIPE, "android_pipe",
+                         "generic,android-pipe", 1, 0, 0);
 
     /* Create mmio transports, so the user can create virtio backends
      * (which will be automatically plugged in to the transports). If
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 8a5a0df..315d128 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -14,6 +14,8 @@
 common-obj-$(CONFIG_A9SCU) += a9scu.o
 common-obj-$(CONFIG_ARM11SCU) += arm11scu.o
 
+obj-$(CONFIG_ANDROID_PIPE) += android_pipe.o
+
 # PKUnity SoC devices
 common-obj-$(CONFIG_PUV3) += puv3_pm.o
 
diff --git a/hw/misc/android_pipe.c b/hw/misc/android_pipe.c
new file mode 100644
index 0000000..90bce95
--- /dev/null
+++ b/hw/misc/android_pipe.c
@@ -0,0 +1,1315 @@
+/* Copyright (C) 2011 The Android Open Source Project
+** Copyright (C) 2014 Linaro Limited
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** Description
+**
+** This device provides a virtual pipe device (originally called
+** goldfish_pipe and latterly qemu_pipe). This allows the android
+** running under the emulator to open a fast connection to the host
+** for various purposes including the adb debug bridge and
+** (eventually) the opengles pass-through. This file contains only the
+** basic pipe infrastructure and a couple of test pipes. Additional
+** pipes are registered with the android_pipe_add_type() call.
+**
+** Open Questions
+**
+** Since this was originally written there have been a number of other
+** virtual devices added to QEMU using the virtio infrastructure. We
+** should give some thought to if this needs re-writing to take
+** advantage of that infrastructure to create the pipes.
+*/
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+
+#include "hw/misc/android_pipe.h"
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "qemu/error-report.h"
+
+/* Set to > 0 for debug output */
+#define PIPE_DEBUG 0
+
+/* Set to 1 to debug i/o register reads/writes */
+#define PIPE_DEBUG_REGS 0
+
+#if PIPE_DEBUG >= 1
+#define D(fmt, ...) \
+    do { fprintf(stdout, "android_pipe: " fmt "\n", ## __VA_ARGS__); } while (0)
+#else
+#define D(fmt, ...)  do { /* nothing */ } while (0)
+#endif
+
+#if PIPE_DEBUG >= 2
+#define DD(fmt, ...) \
+    do { fprintf(stdout, "android_pipe: " fmt "\n", ## __VA_ARGS__); } while (0)
+#else
+#define DD(fmt, ...)  do { /* nothing */ } while (0)
+#endif
+
+#if PIPE_DEBUG_REGS >= 1
+#  define DR(...)   D(__VA_ARGS__)
+#else
+#  define DR(...)   do { /* nothing */ } while (0)
+#endif
+
+#define E(fmt, ...)  \
+    do { fprintf(stdout, "ERROR:" fmt "\n", ## __VA_ARGS__); } while (0)
+
+#define APANIC(...)                     \
+    do {                                \
+        error_report(__VA_ARGS__);      \
+        exit(1);                        \
+    } while (0);
+
+/* Set to 1 to enable the 'zero' pipe type, useful for debugging */
+#define DEBUG_ZERO_PIPE  1
+
+/* Set to 1 to enable the 'pingpong' pipe type, useful for debugging */
+#define DEBUG_PINGPONG_PIPE 1
+
+/* Set to 1 to enable the 'throttle' pipe type, useful for debugging */
+#define DEBUG_THROTTLE_PIPE 1
+
+/* Maximum length of pipe service name, in characters (excluding final 0) */
+#define MAX_PIPE_SERVICE_NAME_SIZE  255
+
+/* from AOSP version include/hw/android/goldfish/device.h
+ * FIXME?: needs to use proper qemu abstractions
+ */
+static inline void uint64_set_low(uint64_t *addr, uint32 value)
+{
+    *addr = (*addr & ~(0xFFFFFFFFULL)) | value;
+}
+
+static inline void uint64_set_high(uint64_t *addr, uint32 value)
+{
+    *addr = (*addr & 0xFFFFFFFFULL) | ((uint64_t)value << 32);
+}
+
+/* FIXME: this is hardcoded for now but will break if used for
+ * lionhead/goldfish (32 bit) */
+static inline gboolean android_guest_is_64bit(void) {
+    return TRUE;
+}
+
+#define TYPE_ANDROID_PIPE "android_pipe"
+#define ANDROID_PIPE(obj) \
+    OBJECT_CHECK(AndroidPipeState, (obj), TYPE_ANDROID_PIPE)
+
+typedef struct PipeDevice  PipeDevice;
+
+typedef struct {
+    SysBusDevice parent;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    /* TODO: roll into shared state */
+    PipeDevice *dev;
+} AndroidPipeState;
+
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****   P I P E   S E R V I C E   R E G I S T R A T I O N
+ *****
+ *****/
+
+#define MAX_PIPE_SERVICES  8
+typedef struct {
+    const char          *name;
+    void                *opaque;        /* pipe specific data */
+    AndroidPipeFuncs    funcs;
+} PipeService;
+
+typedef struct {
+    int          count;
+    PipeService  services[MAX_PIPE_SERVICES];
+} PipeServices;
+
+static PipeServices  _pipeServices[1];
+
+void
+android_pipe_add_type(const char *pipeName,
+                      void *pipeOpaque,
+                      const AndroidPipeFuncs *pipeFuncs)
+{
+    PipeServices *list = _pipeServices;
+    int          count = list->count;
+
+    if (count >= MAX_PIPE_SERVICES) {
+        APANIC("Too many goldfish pipe services (%d)", count);
+    }
+
+    if (strlen(pipeName) > MAX_PIPE_SERVICE_NAME_SIZE) {
+        APANIC("Pipe service name too long: '%s'", pipeName);
+    }
+
+    list->services[count].name   = pipeName;
+    list->services[count].opaque = pipeOpaque;
+    list->services[count].funcs  = pipeFuncs[0];
+
+    list->count++;
+}
+
+static const PipeService* android_pipe_find_type(const char *pipeName)
+{
+    PipeServices* list = _pipeServices;
+    int           count = list->count;
+    int           nn;
+
+    for (nn = 0; nn < count; nn++) {
+        if (!strcmp(list->services[nn].name, pipeName)) {
+            return &list->services[nn];
+        }
+    }
+    return NULL;
+}
+
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    P I P E   C O N N E C T I O N S
+ *****
+ *****/
+
+typedef struct Pipe {
+    struct Pipe                 *next;
+    struct Pipe                 *next_waked;
+    PipeDevice                  *device;
+    uint64_t                    channel; /* opaque kernel handle */
+    void                        *opaque;
+    const AndroidPipeFuncs      *funcs;
+    const PipeService           *service;
+    char*                       args;
+    unsigned char               wanted;
+    char                        closed;
+} Pipe;
+
+/* Forward */
+static void*  pipeConnector_new(Pipe*  pipe);
+
+static Pipe*
+pipe_new0(PipeDevice* dev)
+{
+    Pipe*  pipe;
+    pipe = g_malloc0(sizeof(Pipe));
+    pipe->device = dev;
+    return pipe;
+}
+
+static Pipe*
+pipe_new(uint64_t channel, PipeDevice* dev)
+{
+    Pipe*  pipe = pipe_new0(dev);
+    pipe->channel = channel;
+    pipe->opaque  = pipeConnector_new(pipe);
+    return pipe;
+}
+
+static Pipe**
+pipe_list_findp_channel(Pipe **list, uint64_t channel)
+{
+    Pipe** pnode = list;
+    for (;;) {
+        Pipe* node = *pnode;
+        if (node == NULL || node->channel == channel) {
+            break;
+        }
+        pnode = &node->next;
+    }
+    return pnode;
+}
+
+static Pipe**
+pipe_list_findp_waked(Pipe **list, Pipe *pipe)
+{
+    Pipe** pnode = list;
+    for (;;) {
+        Pipe* node = *pnode;
+        if (node == NULL || node == pipe) {
+            break;
+        }
+        pnode = &node->next_waked;
+    }
+    return pnode;
+}
+
+
+static void pipe_list_remove_waked(Pipe **list, Pipe *pipe)
+{
+    Pipe** lookup = pipe_list_findp_waked(list, pipe);
+    Pipe*  node   = *lookup;
+
+    if (node != NULL) {
+        (*lookup) = node->next_waked;
+        node->next_waked = NULL;
+    }
+}
+
+static void pipe_free(Pipe* pipe)
+{
+    /* Call close callback */
+    if (pipe->funcs->close) {
+        pipe->funcs->close(pipe->opaque);
+    }
+    /* Free stuff */
+    g_free(pipe->args);
+    g_free(pipe);
+}
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    P I P E   C O N N E C T O R S
+ *****
+ *****/
+
+/* These are used to handle the initial connection attempt, where the
+ * client is going to write the name of the pipe service it wants to
+ * connect to, followed by a terminating zero.
+ */
+typedef struct {
+    Pipe*  pipe;
+    char   buffer[128];
+    int    buffpos;
+} PipeConnector;
+
+static const AndroidPipeFuncs  pipeConnector_funcs;  // forward
+
+void*
+pipeConnector_new(Pipe*  pipe)
+{
+    PipeConnector*  pcon;
+
+    pcon = g_malloc0(sizeof(PipeConnector));
+    pcon->pipe  = pipe;
+    pipe->funcs = &pipeConnector_funcs;
+    return pcon;
+}
+
+static void
+pipeConnector_close( void* opaque )
+{
+    PipeConnector*  pcon = opaque;
+    g_free(pcon);
+}
+
+static int
+pipeConnector_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    PipeConnector* pcon = opaque;
+    const AndroidPipeBuffer*  buffers_limit = buffers + numBuffers;
+    int ret = 0;
+
+    DD("%s: channel=0x%llx numBuffers=%d", __FUNCTION__,
+       (unsigned long long)pcon->pipe->channel,
+       numBuffers);
+
+    while (buffers < buffers_limit) {
+        int  avail;
+
+        DD("%s: buffer data (%3zd bytes): '%.*s'", __FUNCTION__,
+           buffers[0].size, (int) buffers[0].size, buffers[0].data);
+
+        if (buffers[0].size == 0) {
+            buffers++;
+            continue;
+        }
+
+        avail = sizeof(pcon->buffer) - pcon->buffpos;
+        if (avail > buffers[0].size)
+            avail = buffers[0].size;
+
+        if (avail > 0) {
+            memcpy(pcon->buffer + pcon->buffpos, buffers[0].data, avail);
+            pcon->buffpos += avail;
+            ret += avail;
+        }
+        buffers++;
+    }
+
+    /* Now check that our buffer contains a zero-terminated string */
+    if (memchr(pcon->buffer, '\0', pcon->buffpos) != NULL) {
+        /* Acceptable formats for the connection string are:
+         *
+         *   pipe:<name>
+         *   pipe:<name>:<arguments>
+         */
+        char* pipeName;
+        char* pipeArgs;
+
+        D("%s: connector: '%s'", __FUNCTION__, pcon->buffer);
+
+        if (memcmp(pcon->buffer, "pipe:", 5) != 0) {
+            /* Nope, we don't handle these for now. */
+            qemu_log_mask(LOG_UNIMP, "%s: Unknown pipe connection: '%s'\n",
+                          __func__, pcon->buffer);
+            return PIPE_ERROR_INVAL;
+        }
+
+        pipeName = pcon->buffer + 5;
+        pipeArgs = strchr(pipeName, ':');
+
+        /* Directly connect qemud:adb pipes to their adb backends without
+         * going through the qemud multiplexer.  All other uses of the ':'
+         * char than an initial "qemud:" will be parsed as arguments to the
+         * pipe name preceeding the colon.
+         */
+        if (pipeArgs && pipeArgs - pipeName == 5
+                && strncmp(pipeName, "qemud", 5) == 0) {
+            pipeArgs = strchr(pipeArgs + 1, ':');
+        }
+
+        if (pipeArgs != NULL) {
+            *pipeArgs++ = '\0';
+            if (!*pipeArgs)
+                pipeArgs = NULL;
+        }
+
+        Pipe* pipe = pcon->pipe;
+        const PipeService* svc = android_pipe_find_type(pipeName);
+        if (svc == NULL) {
+            qemu_log_mask(LOG_UNIMP, "%s: Couldn't find service: '%s'\n",
+                          __func__, pipeName);
+            return PIPE_ERROR_INVAL;
+        }
+
+        void*  peer = svc->funcs.init(pipe, svc->opaque, pipeArgs);
+        if (peer == NULL) {
+            fprintf(stderr,"%s: error initialising pipe:'%s' with args '%s'\n",
+                    __func__, pipeName, pipeArgs);
+            return PIPE_ERROR_INVAL;
+        }
+
+        /* Do the evil switch now */
+        pipe->opaque = peer;
+        pipe->service = svc;
+        pipe->funcs  = &svc->funcs;
+        pipe->args   = g_strdup(pipeArgs);
+        g_free(pcon);
+    }
+
+    return ret;
+}
+
+static int
+pipeConnector_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    return PIPE_ERROR_IO;
+}
+
+static unsigned
+pipeConnector_poll( void* opaque )
+{
+    return PIPE_POLL_OUT;
+}
+
+static void
+pipeConnector_wakeOn( void* opaque, int flags )
+{
+    /* nothing, really should never happen */
+}
+
+static void
+pipeConnector_save( void* pipe, QEMUFile* file )
+{
+    PipeConnector*  pcon = pipe;
+    qemu_put_sbe32(file, pcon->buffpos);
+    qemu_put_sbuffer(file, (const int8_t*)pcon->buffer, pcon->buffpos);
+}
+
+static void*
+pipeConnector_load( void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* file )
+{
+    PipeConnector*  pcon;
+
+    int len = qemu_get_sbe32(file);
+    if (len < 0 || len > sizeof(pcon->buffer)) {
+        return NULL;
+    }
+    pcon = pipeConnector_new(hwpipe);
+    pcon->buffpos = len;
+    if (qemu_get_buffer(file, (uint8_t*)pcon->buffer, pcon->buffpos) != pcon->buffpos) {
+        g_free(pcon);
+        return NULL;
+    }
+    return pcon;
+}
+
+static const AndroidPipeFuncs  pipeConnector_funcs = {
+    NULL,  /* init */
+    pipeConnector_close,        /* should rarely happen */
+    pipeConnector_sendBuffers,  /* the interesting stuff */
+    pipeConnector_recvBuffers,  /* should not happen */
+    pipeConnector_poll,         /* should not happen */
+    pipeConnector_wakeOn,       /* should not happen */
+    pipeConnector_save,
+    pipeConnector_load,
+};
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    Z E R O   P I P E S
+ *****
+ *****/
+
+/* A simple pipe service that mimics /dev/zero, you can write anything to
+ * it, and you can always read any number of zeros from it. Useful for debugging
+ * the kernel driver.
+ */
+#if DEBUG_ZERO_PIPE
+
+typedef struct {
+    void* hwpipe;
+} ZeroPipe;
+
+static void*
+zeroPipe_init( void* hwpipe, void* svcOpaque, const char* args )
+{
+    ZeroPipe*  zpipe;
+
+    D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
+    zpipe = g_malloc0(sizeof(ZeroPipe));
+    zpipe->hwpipe = hwpipe;
+    return zpipe;
+}
+
+static void
+zeroPipe_close( void* opaque )
+{
+    ZeroPipe*  zpipe = opaque;
+
+    D("%s: hwpipe=%p", __FUNCTION__, zpipe->hwpipe);
+    g_free(zpipe);
+}
+
+static int
+zeroPipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    int  ret = 0;
+    while (numBuffers > 0) {
+        ret += buffers[0].size;
+        buffers++;
+        numBuffers--;
+    }
+    return ret;
+}
+
+static int
+zeroPipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    int  ret = 0;
+    while (numBuffers > 0) {
+        ret += buffers[0].size;
+        memset(buffers[0].data, 0, buffers[0].size);
+        buffers++;
+        numBuffers--;
+    }
+    return ret;
+}
+
+static unsigned
+zeroPipe_poll( void* opaque )
+{
+    return PIPE_POLL_IN | PIPE_POLL_OUT;
+}
+
+static void
+zeroPipe_wakeOn( void* opaque, int flags )
+{
+    /* nothing to do here */
+}
+
+static const AndroidPipeFuncs  zeroPipe_funcs = {
+    zeroPipe_init,
+    zeroPipe_close,
+    zeroPipe_sendBuffers,
+    zeroPipe_recvBuffers,
+    zeroPipe_poll,
+    zeroPipe_wakeOn,
+};
+
+#endif /* DEBUG_ZERO */
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    P I N G   P O N G   P I P E S
+ *****
+ *****/
+
+/* Similar debug service that sends back anything it receives */
+/* All data is kept in a circular dynamic buffer */
+
+#if DEBUG_PINGPONG_PIPE
+
+/* Initial buffer size */
+#define PINGPONG_SIZE  1024
+
+typedef struct {
+    void*     hwpipe;
+    uint8_t*  buffer;
+    size_t    size;
+    size_t    pos;
+    size_t    count;
+    unsigned  flags;
+} PingPongPipe;
+
+static void
+pingPongPipe_init0( PingPongPipe* pipe, void* hwpipe, void* svcOpaque )
+{
+    pipe->hwpipe = hwpipe;
+    pipe->size = PINGPONG_SIZE;
+    pipe->buffer = malloc(pipe->size);
+    pipe->pos = 0;
+    pipe->count = 0;
+}
+
+static void*
+pingPongPipe_init( void* hwpipe, void* svcOpaque, const char* args )
+{
+    PingPongPipe*  ppipe;
+
+    D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
+    ppipe = g_malloc0(sizeof(PingPongPipe));
+    pingPongPipe_init0(ppipe, hwpipe, svcOpaque);
+    return ppipe;
+}
+
+static void
+pingPongPipe_close( void* opaque )
+{
+    PingPongPipe*  ppipe = opaque;
+
+    D("%s: hwpipe=%p (pos=%zd count=%zd size=%zd)", __FUNCTION__,
+      ppipe->hwpipe, ppipe->pos, ppipe->count, ppipe->size);
+    free(ppipe->buffer);
+    g_free(ppipe);
+}
+
+static int
+pingPongPipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    PingPongPipe*  pipe = opaque;
+    int  ret = 0;
+    int  count;
+    const AndroidPipeBuffer* buff = buffers;
+    const AndroidPipeBuffer* buffEnd = buff + numBuffers;
+
+    count = 0;
+    for ( ; buff < buffEnd; buff++ )
+        count += buff->size;
+
+    /* Do we need to grow the pingpong buffer? */
+    while (count > pipe->size - pipe->count) {
+        size_t    newsize = pipe->size*2;
+        uint8_t*  newbuff = realloc(pipe->buffer, newsize);
+        int       wpos    = pipe->pos + pipe->count;
+        if (newbuff == NULL) {
+            break;
+        }
+        if (wpos > pipe->size) {
+            wpos -= pipe->size;
+            memcpy(newbuff + pipe->size, newbuff, wpos);
+        }
+        pipe->buffer = newbuff;
+        pipe->size   = newsize;
+        D("pingpong buffer is now %zd bytes", newsize);
+    }
+
+    for ( buff = buffers; buff < buffEnd; buff++ ) {
+        int avail = pipe->size - pipe->count;
+        if (avail <= 0) {
+            if (ret == 0)
+                ret = PIPE_ERROR_AGAIN;
+            break;
+        }
+        if (avail > buff->size) {
+            avail = buff->size;
+        }
+
+        int wpos = pipe->pos + pipe->count;
+        if (wpos >= pipe->size) {
+            wpos -= pipe->size;
+        }
+        if (wpos + avail <= pipe->size) {
+            memcpy(pipe->buffer + wpos, buff->data, avail);
+        } else {
+            int  avail2 = pipe->size - wpos;
+            memcpy(pipe->buffer + wpos, buff->data, avail2);
+            memcpy(pipe->buffer, buff->data + avail2, avail - avail2);
+        }
+        pipe->count += avail;
+        ret += avail;
+    }
+
+    /* Wake up any waiting readers if we wrote something */
+    if (pipe->count > 0 && (pipe->flags & PIPE_WAKE_READ)) {
+        android_pipe_wake(pipe->hwpipe, PIPE_WAKE_READ);
+    }
+
+    return ret;
+}
+
+static int
+pingPongPipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    PingPongPipe*  pipe = opaque;
+    int  ret = 0;
+
+    while (numBuffers > 0) {
+        int avail = pipe->count;
+        if (avail <= 0) {
+            if (ret == 0)
+                ret = PIPE_ERROR_AGAIN;
+            break;
+        }
+        if (avail > buffers[0].size) {
+            avail = buffers[0].size;
+        }
+
+        int rpos = pipe->pos;
+
+        if (rpos + avail <= pipe->size) {
+            memcpy(buffers[0].data, pipe->buffer + rpos, avail);
+        } else {
+            int  avail2 = pipe->size - rpos;
+            memcpy(buffers[0].data, pipe->buffer + rpos, avail2);
+            memcpy(buffers[0].data + avail2, pipe->buffer, avail - avail2);
+        }
+        pipe->count -= avail;
+        pipe->pos   += avail;
+        if (pipe->pos >= pipe->size) {
+            pipe->pos -= pipe->size;
+        }
+        ret += avail;
+        numBuffers--;
+        buffers++;
+    }
+
+    /* Wake up any waiting readers if we wrote something */
+    if (pipe->count < PINGPONG_SIZE && (pipe->flags & PIPE_WAKE_WRITE)) {
+        android_pipe_wake(pipe->hwpipe, PIPE_WAKE_WRITE);
+    }
+
+    return ret;
+}
+
+static unsigned
+pingPongPipe_poll( void* opaque )
+{
+    PingPongPipe*  pipe = opaque;
+    unsigned       ret = 0;
+
+    if (pipe->count < pipe->size)
+        ret |= PIPE_POLL_OUT;
+
+    if (pipe->count > 0)
+        ret |= PIPE_POLL_IN;
+
+    return ret;
+}
+
+static void
+pingPongPipe_wakeOn( void* opaque, int flags )
+{
+    PingPongPipe* pipe = opaque;
+    pipe->flags |= (unsigned)flags;
+}
+
+static const AndroidPipeFuncs  pingPongPipe_funcs = {
+    pingPongPipe_init,
+    pingPongPipe_close,
+    pingPongPipe_sendBuffers,
+    pingPongPipe_recvBuffers,
+    pingPongPipe_poll,
+    pingPongPipe_wakeOn,
+};
+
+#endif /* DEBUG_PINGPONG_PIPE */
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    T H R O T T L E   P I P E S
+ *****
+ *****/
+
+/* Similar to PingPongPipe, but will throttle the bandwidth to test
+ * blocking I/O.
+ */
+
+#ifdef DEBUG_THROTTLE_PIPE
+
+typedef struct {
+    PingPongPipe  pingpong;
+    double        sendRate;
+    int64_t       sendExpiration;
+    double        recvRate;
+    int64_t       recvExpiration;
+    QEMUTimer*    timer;
+} ThrottlePipe;
+
+/* forward declaration */
+static void throttlePipe_timerFunc( void* opaque );
+
+static void*
+throttlePipe_init( void* hwpipe, void* svcOpaque, const char* args )
+{
+    ThrottlePipe* pipe;
+
+    pipe = g_malloc0(sizeof(ThrottlePipe));
+    pingPongPipe_init0(&pipe->pingpong, hwpipe, svcOpaque);
+    pipe->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, throttlePipe_timerFunc, pipe);
+    /* For now, limit to 500 KB/s in both directions */
+    pipe->sendRate = 1e9 / (500*1024*8);
+    pipe->recvRate = pipe->sendRate;
+    return pipe;
+}
+
+static void
+throttlePipe_close( void* opaque )
+{
+    ThrottlePipe* pipe = opaque;
+
+    timer_del(pipe->timer);
+    timer_free(pipe->timer);
+    pingPongPipe_close(&pipe->pingpong);
+}
+
+static void
+throttlePipe_rearm( ThrottlePipe* pipe )
+{
+    int64_t  minExpiration = 0;
+
+    DD("%s: sendExpiration=%" PRId64 " recvExpiration=%" PRId64"\n", __FUNCTION__, pipe->sendExpiration, pipe->recvExpiration);
+
+    if (pipe->sendExpiration) {
+        if (minExpiration == 0 || pipe->sendExpiration < minExpiration)
+            minExpiration = pipe->sendExpiration;
+    }
+
+    if (pipe->recvExpiration) {
+        if (minExpiration == 0 || pipe->recvExpiration < minExpiration)
+            minExpiration = pipe->recvExpiration;
+    }
+
+    if (minExpiration != 0) {
+        DD("%s: Arming for %" PRId64 "\n", __FUNCTION__, minExpiration);
+        timer_mod(pipe->timer, minExpiration);
+    }
+}
+
+static void
+throttlePipe_timerFunc( void* opaque )
+{
+    ThrottlePipe* pipe = opaque;
+    int64_t  now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+    DD("%s: TICK! now=%" PRId64 " sendExpiration=%" PRId64 " recvExpiration=%" PRId64 "\n",
+       __FUNCTION__, now, pipe->sendExpiration, pipe->recvExpiration);
+
+    /* Timer has expired, signal wake up if needed */
+    int      flags = 0;
+
+    if (pipe->sendExpiration && now > pipe->sendExpiration) {
+        flags |= PIPE_WAKE_WRITE;
+        pipe->sendExpiration = 0;
+    }
+    if (pipe->recvExpiration && now > pipe->recvExpiration) {
+        flags |= PIPE_WAKE_READ;
+        pipe->recvExpiration = 0;
+    }
+    flags &= pipe->pingpong.flags;
+    if (flags != 0) {
+        DD("%s: WAKE %d\n", __FUNCTION__, flags);
+        android_pipe_wake(pipe->pingpong.hwpipe, flags);
+    }
+
+    throttlePipe_rearm(pipe);
+}
+
+static int
+throttlePipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    ThrottlePipe*  pipe = opaque;
+    int            ret;
+
+    if (pipe->sendExpiration > 0) {
+        return PIPE_ERROR_AGAIN;
+    }
+
+    ret = pingPongPipe_sendBuffers(&pipe->pingpong, buffers, numBuffers);
+    if (ret > 0) {
+        /* Compute next send expiration time */
+        pipe->sendExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->sendRate;
+        throttlePipe_rearm(pipe);
+    }
+    return ret;
+}
+
+static int
+throttlePipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    ThrottlePipe* pipe = opaque;
+    int           ret;
+
+    if (pipe->recvExpiration > 0) {
+        return PIPE_ERROR_AGAIN;
+    }
+
+    ret = pingPongPipe_recvBuffers(&pipe->pingpong, buffers, numBuffers);
+    if (ret > 0) {
+        pipe->recvExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->recvRate;
+        throttlePipe_rearm(pipe);
+    }
+    return ret;
+}
+
+static unsigned
+throttlePipe_poll( void* opaque )
+{
+    ThrottlePipe*  pipe = opaque;
+    unsigned       ret  = pingPongPipe_poll(&pipe->pingpong);
+
+    if (pipe->sendExpiration > 0)
+        ret &= ~PIPE_POLL_OUT;
+
+    if (pipe->recvExpiration > 0)
+        ret &= ~PIPE_POLL_IN;
+
+    return ret;
+}
+
+static void
+throttlePipe_wakeOn( void* opaque, int flags )
+{
+    ThrottlePipe* pipe = opaque;
+    pingPongPipe_wakeOn(&pipe->pingpong, flags);
+}
+
+static const AndroidPipeFuncs  throttlePipe_funcs = {
+    throttlePipe_init,
+    throttlePipe_close,
+    throttlePipe_sendBuffers,
+    throttlePipe_recvBuffers,
+    throttlePipe_poll,
+    throttlePipe_wakeOn,
+};
+
+#endif /* DEBUG_THROTTLE_PIPE */
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    G O L D F I S H   P I P E   D E V I C E
+ *****
+ *****/
+
+struct PipeDevice {
+    AndroidPipeState *ps;       /* FIXME: backlink to instance state */
+
+    /* the list of all pipes */
+    Pipe*  pipes;
+
+    /* the list of signalled pipes */
+    Pipe*  signaled_pipes;
+
+    /* i/o registers */
+    uint64_t  address;
+    uint32_t  size;
+    uint32_t  status;
+    uint64_t  channel;
+    uint32_t  wakes;
+    uint64_t  params_addr;
+};
+
+/* Map the guest buffer specified by the guest vaddr 'address'.
+ * Returns a host pointer which should be unmapped later via
+ * cpu_physical_memory_unmap(), or NULL if mapping failed (likely
+ * because the vaddr doesn't actually point at RAM).
+ * Note that for RAM the "mapping" process doesn't actually involve a
+ * data copy.
+ *
+ * TODO: using cpu_get_phys_page_debug() is a bit bogus, and we could
+ * avoid it if we fixed the driver to do the sane thing and pass us
+ * physical addresses rather than virtual ones.
+ */
+static void *map_guest_buffer(target_ulong address, size_t size, int is_write)
+{
+    hwaddr l = size;
+    void *ptr;
+
+    /* Convert virtual address to physical address */
+    hwaddr phys = cpu_get_phys_page_debug(current_cpu, address);
+
+    if (phys == -1) {
+        return NULL;
+    }
+
+    ptr = cpu_physical_memory_map(phys, &l, is_write);
+    if (!ptr) {
+        /* Can't happen for RAM */
+        return NULL;
+    }
+    if (l != size) {
+        /* This will only happen if the address pointed at non-RAM,
+         * or if the size means the buffer end is beyond the end of
+         * the RAM block.
+         */
+        cpu_physical_memory_unmap(ptr, l, 0, 0);
+        return NULL;
+    }
+
+    return ptr;
+}
+
+static void
+pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
+{
+    Pipe** lookup = pipe_list_findp_channel(&dev->pipes, dev->channel);
+    Pipe*  pipe   = *lookup;
+
+    /* Check that we're referring a known pipe channel */
+    if (command != PIPE_CMD_OPEN && pipe == NULL) {
+        dev->status = PIPE_ERROR_INVAL;
+        return;
+    }
+
+    /* If the pipe is closed by the host, return an error */
+    if (pipe != NULL && pipe->closed && command != PIPE_CMD_CLOSE) {
+        dev->status = PIPE_ERROR_IO;
+        return;
+    }
+
+    switch (command) {
+    case PIPE_CMD_OPEN:
+        DD("%s: CMD_OPEN channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        if (pipe != NULL) {
+            dev->status = PIPE_ERROR_INVAL;
+            break;
+        }
+        pipe = pipe_new(dev->channel, dev);
+        pipe->next = dev->pipes;
+        dev->pipes = pipe;
+        dev->status = 0;
+        break;
+
+    case PIPE_CMD_CLOSE:
+        DD("%s: CMD_CLOSE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        /* Remove from device's lists */
+        *lookup = pipe->next;
+        pipe->next = NULL;
+        pipe_list_remove_waked(&dev->signaled_pipes, pipe);
+        pipe_free(pipe);
+        break;
+
+    case PIPE_CMD_POLL:
+        dev->status = pipe->funcs->poll(pipe->opaque);
+        DD("%s: CMD_POLL > status=%d", __FUNCTION__, dev->status);
+        break;
+
+    case PIPE_CMD_READ_BUFFER: {
+        /* Translate virtual address into physical one, into emulator memory. */
+        AndroidPipeBuffer  buffer;
+        buffer.data = map_guest_buffer(dev->address, dev->size, 1);
+        if (!buffer.data) {
+            dev->status = PIPE_ERROR_INVAL;
+            break;
+        }
+        buffer.size = dev->size;
+        dev->status = pipe->funcs->recvBuffers(pipe->opaque, &buffer, 1);
+        DD("%s: CMD_READ_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
+           __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
+           dev->size, dev->status);
+        cpu_physical_memory_unmap(buffer.data, dev->size, 1, dev->size);
+        break;
+    }
+
+    case PIPE_CMD_WRITE_BUFFER: {
+        /* Translate virtual address into physical one, into emulator memory. */
+        AndroidPipeBuffer  buffer;
+        buffer.data = map_guest_buffer(dev->address, dev->size, 0);
+        if (!buffer.data) {
+            dev->status = PIPE_ERROR_INVAL;
+            break;
+        }
+        buffer.size = dev->size;
+        dev->status = pipe->funcs->sendBuffers(pipe->opaque, &buffer, 1);
+        DD("%s: CMD_WRITE_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
+           __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
+           dev->size, dev->status);
+        cpu_physical_memory_unmap(buffer.data, dev->size, 0, dev->size);
+        break;
+    }
+
+    case PIPE_CMD_WAKE_ON_READ:
+        DD("%s: CMD_WAKE_ON_READ channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        if ((pipe->wanted & PIPE_WAKE_READ) == 0) {
+            pipe->wanted |= PIPE_WAKE_READ;
+            pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
+        }
+        dev->status = 0;
+        break;
+
+    case PIPE_CMD_WAKE_ON_WRITE:
+        DD("%s: CMD_WAKE_ON_WRITE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        if ((pipe->wanted & PIPE_WAKE_WRITE) == 0) {
+            pipe->wanted |= PIPE_WAKE_WRITE;
+            pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
+        }
+        dev->status = 0;
+        break;
+
+    default:
+        D("%s: command=%d (0x%x)\n", __FUNCTION__, command, command);
+    }
+}
+
+static void pipe_dev_write(void *opaque, hwaddr offset, uint64_t value, unsigned size)
+{
+    AndroidPipeState *state = (AndroidPipeState *) opaque;
+    PipeDevice *s = state->dev;
+
+    DR("%s: offset = 0x%" HWADDR_PRIx " value=%" PRIu64 "/0x%" PRIx64,
+       __func__, offset, value, value);
+    switch (offset) {
+    case PIPE_REG_COMMAND:
+        pipeDevice_doCommand(s, value);
+        break;
+
+    case PIPE_REG_SIZE:
+        s->size = value;
+        break;
+
+    case PIPE_REG_ADDRESS:
+        uint64_set_low(&s->address, value);
+        break;
+
+    case PIPE_REG_ADDRESS_HIGH:
+        uint64_set_high(&s->address, value);
+        break;
+
+    case PIPE_REG_CHANNEL:
+        uint64_set_low(&s->channel, value);
+        break;
+
+    case PIPE_REG_CHANNEL_HIGH:
+        uint64_set_high(&s->channel, value);
+        break;
+
+    case PIPE_REG_PARAMS_ADDR_HIGH:
+        uint64_set_high(&s->params_addr, value);
+        break;
+
+    case PIPE_REG_PARAMS_ADDR_LOW:
+        uint64_set_low(&s->params_addr, value);
+        break;
+
+    case PIPE_REG_ACCESS_PARAMS:
+    {
+        struct access_params aps;
+        struct access_params_64 aps64;
+        uint32_t cmd;
+
+        /* Don't touch aps.result if anything wrong */
+        if (s->params_addr == 0)
+            break;
+
+        if (android_guest_is_64bit()) {
+            cpu_physical_memory_read(s->params_addr, (void*)&aps64,
+                                     sizeof(aps64));
+            s->channel = aps64.channel;
+            s->size = aps64.size;
+            s->address = aps64.address;
+            cmd = aps64.cmd;
+        } else {
+            cpu_physical_memory_read(s->params_addr, (void*)&aps,
+                                     sizeof(aps));
+            s->channel = aps.channel;
+            s->size = aps.size;
+            s->address = aps.address;
+            cmd = aps.cmd;
+        }
+
+        if ((cmd != PIPE_CMD_READ_BUFFER) && (cmd != PIPE_CMD_WRITE_BUFFER))
+            break;
+
+        pipeDevice_doCommand(s, cmd);
+
+        if (android_guest_is_64bit()) {
+            aps64.result = s->status;
+            cpu_physical_memory_write(s->params_addr, (void*)&aps64,
+                                      sizeof(aps64));
+        } else {
+            aps.result = s->status;
+            cpu_physical_memory_write(s->params_addr, (void*)&aps,
+                                      sizeof(aps));
+        }
+    }
+    break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register offset = 0x%"
+                      HWADDR_PRIx " value=%" PRIu64 "/0x%" PRIx64 "\n",
+                      __func__, offset, value, value);
+        break;
+    }
+}
+
+/* I/O read */
+static uint64_t pipe_dev_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AndroidPipeState *s = (AndroidPipeState *)opaque;
+    PipeDevice *dev = s->dev;
+
+    switch (offset) {
+    case PIPE_REG_STATUS:
+        DR("%s: REG_STATUS status=%d (0x%x)", __FUNCTION__, dev->status, dev->status);
+        return dev->status;
+
+    case PIPE_REG_CHANNEL:
+        if (dev->signaled_pipes != NULL) {
+            Pipe* pipe = dev->signaled_pipes;
+            DR("%s: channel=0x%llx wanted=%d", __FUNCTION__,
+               (unsigned long long)pipe->channel, pipe->wanted);
+            dev->wakes = pipe->wanted;
+            pipe->wanted = 0;
+            dev->signaled_pipes = pipe->next_waked;
+            pipe->next_waked = NULL;
+            if (dev->signaled_pipes == NULL) {
+                /* android_device_set_irq(&dev->dev, 0, 0); */
+                qemu_set_irq(s->irq, 0);
+                DD("%s: lowering IRQ", __FUNCTION__);
+            }
+            return (uint32_t)(pipe->channel & 0xFFFFFFFFUL);
+        }
+        DR("%s: no signaled channels", __FUNCTION__);
+        return 0;
+
+    case PIPE_REG_CHANNEL_HIGH:
+        if (dev->signaled_pipes != NULL) {
+            Pipe* pipe = dev->signaled_pipes;
+            DR("%s: channel_high=0x%llx wanted=%d", __FUNCTION__,
+               (unsigned long long)pipe->channel, pipe->wanted);
+            return (uint32_t)(pipe->channel >> 32);
+        }
+        DR("%s: no signaled channels", __FUNCTION__);
+        return 0;
+
+    case PIPE_REG_WAKES:
+        DR("%s: wakes %d", __FUNCTION__, dev->wakes);
+        return dev->wakes;
+
+    case PIPE_REG_PARAMS_ADDR_HIGH:
+        return (uint32_t)(dev->params_addr >> 32);
+
+    case PIPE_REG_PARAMS_ADDR_LOW:
+        return (uint32_t)(dev->params_addr & 0xFFFFFFFFUL);
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register %" HWADDR_PRId
+                      " (0x%" HWADDR_PRIx ")\n", __FUNCTION__, offset, offset);
+    }
+    return 0;
+}
+
+static const MemoryRegionOps android_pipe_iomem_ops = {
+    .read = pipe_dev_read,
+    .write = pipe_dev_write,
+    .endianness = DEVICE_NATIVE_ENDIAN
+};
+
+static void android_pipe_realize(DeviceState *dev, Error **errp)
+{
+    SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
+    AndroidPipeState *s = ANDROID_PIPE(dev);
+
+    s->dev = (PipeDevice *) g_malloc0(sizeof(PipeDevice));
+    s->dev->ps = s; /* HACK: backlink */
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &android_pipe_iomem_ops, s,
+                          "android_pipe", 0x1000 /*TODO: ?how big?*/);
+    sysbus_init_mmio(sbdev, &s->iomem);
+    sysbus_init_irq(sbdev, &s->irq);
+
+#if DEBUG_ZERO_PIPE
+    android_pipe_add_type("zero", NULL, &zeroPipe_funcs);
+#endif
+#if DEBUG_PINGPONG_PIPE
+    android_pipe_add_type("pingpong", NULL, &pingPongPipe_funcs);
+#endif
+#if DEBUG_THROTTLE_PIPE
+    android_pipe_add_type("throttle", NULL, &throttlePipe_funcs);
+#endif
+}
+
+void
+android_pipe_wake( void* hwpipe, unsigned flags )
+{
+    Pipe*  pipe = hwpipe;
+    Pipe** lookup;
+    PipeDevice*  dev = pipe->device;
+
+    DD("%s: channel=0x%llx flags=%d", __FUNCTION__, (unsigned long long)pipe->channel, flags);
+
+    /* If not already there, add to the list of signaled pipes */
+    lookup = pipe_list_findp_waked(&dev->signaled_pipes, pipe);
+    if (!*lookup) {
+        pipe->next_waked = dev->signaled_pipes;
+        dev->signaled_pipes = pipe;
+    }
+    pipe->wanted |= (unsigned)flags;
+
+    /* Raise IRQ to indicate there are items on our list ! */
+    /* android_device_set_irq(&dev->dev, 0, 1);*/
+    qemu_set_irq(dev->ps->irq, 1);
+    DD("%s: raising IRQ", __FUNCTION__);
+}
+
+void
+android_pipe_close( void* hwpipe )
+{
+    Pipe* pipe = hwpipe;
+
+    D("%s: channel=0x%llx (closed=%d)", __FUNCTION__, (unsigned long long)pipe->channel, pipe->closed);
+
+    if (!pipe->closed) {
+        pipe->closed = 1;
+        android_pipe_wake( hwpipe, PIPE_WAKE_CLOSED );
+    }
+}
+
+static void android_pipe_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = android_pipe_realize;
+    dc->desc = "android pipe";
+}
+
+static const TypeInfo android_pipe_info = {
+    .name          = TYPE_ANDROID_PIPE,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AndroidPipeState),
+    .class_init    = android_pipe_class_init
+};
+
+static void android_pipe_register(void)
+{
+    type_register_static(&android_pipe_info);
+}
+
+type_init(android_pipe_register);
diff --git a/include/hw/misc/android_pipe.h b/include/hw/misc/android_pipe.h
new file mode 100644
index 0000000..3fa7e18
--- /dev/null
+++ b/include/hw/misc/android_pipe.h
@@ -0,0 +1,220 @@
+/* Copyright (C) 2011 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#ifndef _HW_ANDROID_PIPE_H
+#define _HW_ANDROID_PIPE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "hw/hw.h"
+
+/* TECHNICAL NOTE:
+ *
+ * A android pipe is a very fast communication channel between the guest
+ * system and the emulator program.
+ *
+ * To open a new pipe to the emulator, a guest client will do the following:
+ *
+ *     fd = open("/dev/qemu_pipe", O_RDWR);
+ *     char  invite[64];
+ *     snprintf(invite, sizeof invite, "%s", pipeName);
+ *     ret = write(fd, invite, strlen(invite));
+ *
+ *     if (ret < 0) {
+ *         // something bad happened, see errno
+ *     }
+ *
+ *     now read()/write() to communicate with <pipeName> service in the
+ *     emulator.
+ *
+ * This header provides the interface used by pipe services in the emulator
+ * to receive new client connection and deal with them.
+ *
+ *
+ * 1/ Call android_pipe_add_type() to register a new pipe service by name.
+ *    This must provide a pointer to a series of functions that will be called
+ *    during normal pipe operations.
+ *
+ * 2/ When a client connects to the service, the 'init' callback will be called
+ *    to create a new service-specific client identifier (which must returned
+ *    by the function).
+ *
+ * 3/ Call android_pipe_close() to force the closure of a given pipe.
+ *
+ * 4/ Call android_pipe_signal() to signal a change of state to the pipe.
+ *
+ */
+
+/* Buffer descriptor for sendBuffers() and recvBuffers() callbacks */
+typedef struct AndroidPipeBuffer {
+    uint8_t*  data;
+    size_t    size;
+} AndroidPipeBuffer;
+
+/* Pipe handler funcs */
+typedef struct {
+    /* Create new client connection, 'hwpipe' must be passed to other
+     * android_pipe_xxx functions, while the returned value will be passed
+     * to other callbacks (e.g. close). 'pipeOpaque' is the value passed
+     * to android_pipe_add_type() when registering a given pipe service.
+     */
+    void*        (*init)( void* hwpipe, void* pipeOpaque, const char* args );
+
+    /* Called when the guest kernel has finally closed a pipe connection.
+     * This is the only place where you can release/free the client connection.
+     * You should never invoke this callback directly. Call android_pipe_close()
+     * instead.
+     */
+    void         (*close)( void* pipe );
+
+    /* Called when the guest is write()-ing to the pipe. Should return the
+     * number of bytes transfered, 0 for EOF status, or a negative error
+     * value otherwise, including PIPE_ERROR_AGAIN to indicate that the
+     * emulator is not ready to receive data yet.
+     */
+    int          (*sendBuffers)( void* pipe, const AndroidPipeBuffer*  buffers, int numBuffers );
+
+    /* Same as sendBuffers when the guest is read()-ing from the pipe. */
+    int          (*recvBuffers)( void* pipe, AndroidPipeBuffer* buffers, int numBuffers );
+
+    /* Called when guest wants to poll the read/write status for the pipe.
+     * Should return a combination of PIPE_POLL_XXX flags.
+     */
+    unsigned     (*poll)( void* pipe );
+
+    /* Called to signal that the guest wants to be woken when the set of
+     * PIPE_WAKE_XXX bit-flags in 'flags' occur. When the condition occurs,
+     * then the pipe implementation shall call android_pipe_wake().
+     */
+    void         (*wakeOn)( void* opaque, int flags );
+
+    /* Called to save the pipe's state to a QEMUFile, i.e. when saving
+     * snapshots. This can be NULL to indicate that no state can be saved.
+     * In this case, when the pipe is loaded, the emulator will automatically
+     * force-close so the next operation the guest performs on it will return
+     * a PIPE_ERROR_IO error code.
+     */
+    void         (*save)( void* pipe, QEMUFile* file );
+
+    /* Called to load the sate of a pipe from a QEMUFile. This will always
+     * correspond to the state of the pipe as saved by a previous call to
+     * the 'save' method. Can be NULL to indicate that the pipe state cannot
+     * be loaded. In this case, the emulator will automatically force-close
+     * it.
+     *
+     * In case of success, this returns 0, and the new pipe object is returned
+     * in '*ppipe'. In case of errno code is returned to indicate a failure.
+     * 'hwpipe' and 'pipeOpaque' are the same arguments than those passed
+     * to 'init'.
+     */
+    void*        (*load)( void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* file);
+} AndroidPipeFuncs;
+
+/* Register a new pipe handler type. 'pipeOpaque' is passed directly
+ * to 'init() when a new pipe is connected to.
+ */
+extern void  android_pipe_add_type(const char*               pipeName,
+                                     void*                     pipeOpaque,
+                                     const AndroidPipeFuncs*  pipeFuncs );
+
+/* This tells the guest system that we want to close the pipe and that
+ * further attempts to read or write to it will fail. This will not
+ * necessarily call the 'close' callback immediately though.
+ *
+ * This will also wake-up any blocked guest threads waiting for i/o.
+ */
+extern void android_pipe_close( void* hwpipe );
+
+/* Signal that the pipe can be woken up. 'flags' must be a combination of
+ * PIPE_WAKE_READ and PIPE_WAKE_WRITE.
+ */
+extern void android_pipe_wake( void* hwpipe, unsigned flags );
+
+/* The following definitions must match those in the kernel driver:
+ *
+ * For goldfish:
+ *   android.googlesource.com/kernel/goldfish.git.
+ *   $KERNEL/drivers/misc/qemupipe/qemu_pipe.c
+ *
+ * For ranchu:
+ *   android.googlesource.com/kernel/common.git
+ *   $KERNEL/drivers/staging/android/android_pipe.c
+ */
+
+/* pipe device registers */
+#define PIPE_REG_COMMAND            0x00  /* write: value = command */
+#define PIPE_REG_STATUS             0x04  /* read */
+#define PIPE_REG_CHANNEL            0x08  /* read/write: channel id */
+#define PIPE_REG_SIZE               0x0c  /* read/write: buffer size */
+#define PIPE_REG_ADDRESS            0x10  /* write: physical address */
+#define PIPE_REG_WAKES              0x14  /* read: wake flags */
+/* read/write: parameter buffer address */
+#define PIPE_REG_PARAMS_ADDR_LOW     0x18
+#define PIPE_REG_PARAMS_ADDR_HIGH    0x1c
+/* write: access with paremeter buffer */
+#define PIPE_REG_ACCESS_PARAMS       0x20
+#define PIPE_REG_CHANNEL_HIGH        0x30 /* read/write: high 32 bit channel id */
+#define PIPE_REG_ADDRESS_HIGH        0x34 /* write: high 32 bit physical address */
+
+/* list of commands for PIPE_REG_COMMAND */
+#define PIPE_CMD_OPEN               1  /* open new channel */
+#define PIPE_CMD_CLOSE              2  /* close channel (from guest) */
+#define PIPE_CMD_POLL               3  /* poll read/write status */
+
+/* List of bitflags returned in status of CMD_POLL command */
+#define PIPE_POLL_IN   (1 << 0)
+#define PIPE_POLL_OUT  (1 << 1)
+#define PIPE_POLL_HUP  (1 << 2)
+
+/* The following commands are related to write operations */
+#define PIPE_CMD_WRITE_BUFFER       4  /* send a user buffer to the emulator */
+#define PIPE_CMD_WAKE_ON_WRITE      5  /* tell the emulator to wake us when writing is possible */
+
+/* The following commands are related to read operations, they must be
+ * listed in the same order than the corresponding write ones, since we
+ * will use (CMD_READ_BUFFER - CMD_WRITE_BUFFER) as a special offset
+ * in qemu_pipe_read_write() below.
+ */
+#define PIPE_CMD_READ_BUFFER        6  /* receive a page-contained buffer from the emulator */
+#define PIPE_CMD_WAKE_ON_READ       7  /* tell the emulator to wake us when reading is possible */
+
+/* Possible status values used to signal errors - see qemu_pipe_error_convert */
+#define PIPE_ERROR_INVAL       -1
+#define PIPE_ERROR_AGAIN       -2
+#define PIPE_ERROR_NOMEM       -3
+#define PIPE_ERROR_IO          -4
+
+/* Bit-flags used to signal events from the emulator */
+#define PIPE_WAKE_CLOSED       (1 << 0)  /* emulator closed pipe */
+#define PIPE_WAKE_READ         (1 << 1)  /* pipe can now be read from */
+#define PIPE_WAKE_WRITE        (1 << 2)  /* pipe can now be written to */
+
+struct access_params{
+    uint32_t channel;
+    uint32_t size;
+    uint32_t address;
+    uint32_t cmd;
+    uint32_t result;
+    /* reserved for future extension */
+    uint32_t flags;
+};
+
+struct access_params_64 {
+    uint64_t channel;
+    uint32_t size;
+    uint64_t address;
+    uint32_t cmd;
+    uint32_t result;
+    /* reserved for future extension */
+    uint32_t flags;
+};
+
+#endif /* _HW_ANDROID_PIPE_H */