goldfish: enable 64 bit goldfish audio device

Enable the 64 bit audio device emulation in the goldfish platform.

Change-Id: Ia3d289b52d9acdc8d3a7b18e66a0476496e9a489
Signed-off-by: Jun Tian <jun.j.tian@intel.com>
diff --git a/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT b/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
index d375d4c..88220e8 100644
--- a/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
+++ b/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
@@ -502,6 +502,11 @@
     0x20  START_READ
     0x24  READ_BUFFER_AVAILABLE
 
+    # For 64-bit guest CPUs
+    0x28  SET_WRITE_BUFFER_1_HIGH  W: Set high 32 bits of 1st kernel output buffer address.
+    0x30  SET_WRITE_BUFFER_2_HIGH  W: Set high 32 bits  of 2nd kernel output buffer address.
+    0x34  SET_READ_BUFFER_HIGH     W: Set high 32 bits of kernel input buffer address.
+
 This device implements a virtual sound card with the following properties:
 
   - Stereo output at fixed 44.1 kHz frequency, using signed 16-bit samples.
@@ -511,9 +516,14 @@
     Optional.
 
 For output, the kernel driver allocates two internal buffers to hold output
-samples, and passes their physical address with
-IO_WRITE(SET_WRITE_BUFFER_1, <buffer1>) and
-IO_WRITE(SET_WRITE_BUFFER_2, <buffer2>).
+samples, and passes their physical address to the emulator as follows:
+
+  #if 64BIT_GUEST_CPU
+  IO_WRITE(SET_WRITE_BUFFER_1_HIGH, (uint32_t)(buffer1 >> 32));
+  IO_WRITE(SET_WRITE_BUFFER_2_HIGH, (uint32_t)(buffer2 >> 32));
+  #endif
+  IO_WRITE(SET_WRITE_BUFFER_1, (uint32_t)buffer1);
+  IO_WRITE(SET_WRITE_BUFFER_2, (uint32_t)buffer2);
 
 After this, samples will be sent from the driver to the virtual device by
 using one of IO_WRITE(WRITE_BUFFER_1, <length1>) or
@@ -540,9 +550,10 @@
 For input, the driver should first IO_READ(READ_SUPPORTED), which will return 1
 if the virtual device supports input, or 0 otherwise. If it does support it,
 the driver must allocate an internal buffer and send its physical address with
-IO_WRITE(SET_READ_BUFFER, <read-buffer>), then perform
-IO_WRITE(START_READ, <read-buffer-length>) to start recording and specify
-the kernel's buffer length.
+IO_WRITE(SET_READ_BUFFER, <read-buffer>) (with a previous write to
+SET_READ_BUFFER_HIGH on 64-bit guest CPUS), then perform
+IO_WRITE(START_READ, <read-buffer-length>) to start recording and
+specify the kernel's buffer length.
 
 Later, the device will raise its IRQ and set bit2 of 'int_status' to indicate
 there are incoming samples to the driver. In its interrupt handler, the latter
diff --git a/hw/android/goldfish/audio.c b/hw/android/goldfish/audio.c
index ce0b642..228a7ca 100644
--- a/hw/android/goldfish/audio.c
+++ b/hw/android/goldfish/audio.c
@@ -34,38 +34,43 @@
 #define  USE_QEMU_AUDIO_IN  1
 
 enum {
-	/* audio status register */
-	AUDIO_INT_STATUS	= 0x00,
-	/* set this to enable IRQ */
-	AUDIO_INT_ENABLE	= 0x04,
-	/* set these to specify buffer addresses */
-	AUDIO_SET_WRITE_BUFFER_1 = 0x08,
-	AUDIO_SET_WRITE_BUFFER_2 = 0x0C,
-	/* set number of bytes in buffer to write */
-	AUDIO_WRITE_BUFFER_1  = 0x10,
-	AUDIO_WRITE_BUFFER_2  = 0x14,
+    /* audio status register */
+    AUDIO_INT_STATUS	= 0x00,
+    /* set this to enable IRQ */
+    AUDIO_INT_ENABLE	= 0x04,
+    /* set these to specify buffer addresses */
+    AUDIO_SET_WRITE_BUFFER_1 = 0x08,
+    AUDIO_SET_WRITE_BUFFER_2 = 0x0C,
+    /* set number of bytes in buffer to write */
+    AUDIO_WRITE_BUFFER_1  = 0x10,
+    AUDIO_WRITE_BUFFER_2  = 0x14,
 
-	/* true if audio input is supported */
-	AUDIO_READ_SUPPORTED = 0x18,
-	/* buffer to use for audio input */
-	AUDIO_SET_READ_BUFFER = 0x1C,
+    /* true if audio input is supported */
+    AUDIO_READ_SUPPORTED = 0x18,
+    /* buffer to use for audio input */
+    AUDIO_SET_READ_BUFFER = 0x1C,
 
-	/* driver writes number of bytes to read */
-	AUDIO_START_READ  = 0x20,
+    /* driver writes number of bytes to read */
+    AUDIO_START_READ  = 0x20,
 
-	/* number of bytes available in read buffer */
-	AUDIO_READ_BUFFER_AVAILABLE  = 0x24,
+    /* number of bytes available in read buffer */
+    AUDIO_READ_BUFFER_AVAILABLE  = 0x24,
 
-	/* AUDIO_INT_STATUS bits */
+    /* for 64-bit guest CPUs only */
+    AUDIO_SET_WRITE_BUFFER_1_HIGH = 0x28,
+    AUDIO_SET_WRITE_BUFFER_2_HIGH = 0x30,
+    AUDIO_SET_READ_BUFFER_HIGH = 0x34,
 
-	/* this bit set when it is safe to write more bytes to the buffer */
-	AUDIO_INT_WRITE_BUFFER_1_EMPTY	= 1U << 0,
-	AUDIO_INT_WRITE_BUFFER_2_EMPTY	= 1U << 1,
-	AUDIO_INT_READ_BUFFER_FULL      = 1U << 2,
+    /* AUDIO_INT_STATUS bits */
+
+    /* this bit set when it is safe to write more bytes to the buffer */
+    AUDIO_INT_WRITE_BUFFER_1_EMPTY = 1U << 0,
+    AUDIO_INT_WRITE_BUFFER_2_EMPTY = 1U << 1,
+    AUDIO_INT_READ_BUFFER_FULL     = 1U << 2,
 };
 
 struct goldfish_audio_buff {
-    uint32_t  address;
+    uint64_t  address;
     uint32_t  length;
     uint8*    data;
     uint32_t  capacity;
@@ -147,7 +152,13 @@
 static void
 goldfish_audio_buff_set_address( struct goldfish_audio_buff*  b, uint32_t  addr )
 {
-    b->address = addr;
+    uint64_set_low(&b->address, addr);
+}
+
+static void
+goldfish_audio_buff_set_address_high( struct goldfish_audio_buff*  b, uint32_t  addr )
+{
+    uint64_set_high(&b->address, addr);
 }
 
 static void
@@ -210,27 +221,8 @@
     return read;
 }
 
-static void
-goldfish_audio_buff_put( struct goldfish_audio_buff*  b, QEMUFile*  f )
-{
-    qemu_put_be32(f, b->address );
-    qemu_put_be32(f, b->length );
-    qemu_put_be32(f, b->offset );
-    qemu_put_buffer(f, b->data, b->length );
-}
-
-static void
-goldfish_audio_buff_get( struct goldfish_audio_buff*  b, QEMUFile*  f )
-{
-    b->address = qemu_get_be32(f);
-    b->length  = qemu_get_be32(f);
-    b->offset  = qemu_get_be32(f);
-    goldfish_audio_buff_ensure(b, b->length);
-    qemu_get_buffer(f, b->data, b->length);
-}
-
 /* update this whenever you change the goldfish_audio_state structure */
-#define  AUDIO_STATE_SAVE_VERSION  2
+#define  AUDIO_STATE_SAVE_VERSION  3
 
 #define  QFIELD_STRUCT   struct goldfish_audio_state
 QFIELD_BEGIN(audio_state_fields)
@@ -240,6 +232,28 @@
     QFIELD_INT32(current_buffer),
 QFIELD_END
 
+static void
+goldfish_audio_buff_put( struct goldfish_audio_buff*  b, QEMUFile*  f )
+{
+    qemu_put_be64(f, b->address );
+    qemu_put_be32(f, b->length );
+    qemu_put_be32(f, b->offset );
+    qemu_put_buffer(f, b->data, b->length );
+}
+
+static void
+goldfish_audio_buff_get( struct goldfish_audio_buff*  b, QEMUFile*  f, int version_id )
+{
+    if (version_id ==  (AUDIO_STATE_SAVE_VERSION - 1))
+        b->address = (uint64_t)qemu_get_be32(f);
+    else
+        b->address = qemu_get_be64(f);
+    b->length  = qemu_get_be32(f);
+    b->offset  = qemu_get_be32(f);
+    goldfish_audio_buff_ensure(b, b->length);
+    qemu_get_buffer(f, b->data, b->length);
+}
+
 static void  audio_state_save( QEMUFile*  f, void* opaque )
 {
     struct goldfish_audio_state*  s = opaque;
@@ -256,14 +270,15 @@
     struct goldfish_audio_state*  s = opaque;
     int                           ret;
 
-    if (version_id != AUDIO_STATE_SAVE_VERSION)
+    if ((version_id != AUDIO_STATE_SAVE_VERSION) && 
+        (version_id != (AUDIO_STATE_SAVE_VERSION - 1))) {
         return -1;
-
+    }
     ret = qemu_get_struct(f, audio_state_fields, s);
     if (!ret) {
-        goldfish_audio_buff_get( s->out_buff1, f );
-        goldfish_audio_buff_get( s->out_buff2, f );
-        goldfish_audio_buff_get (s->in_buff, f);
+        goldfish_audio_buff_get( s->out_buff1, f, version_id);
+        goldfish_audio_buff_get( s->out_buff2, f, version_id);
+        goldfish_audio_buff_get (s->in_buff, f, version_id);
     }
 
     // Similar to enable_audio - without the buffer reset.
@@ -427,11 +442,21 @@
             D( "%s: AUDIO_SET_WRITE_BUFFER_1 %08x", __FUNCTION__, val);
             goldfish_audio_buff_set_address( s->out_buff1, val );
             break;
+        case AUDIO_SET_WRITE_BUFFER_1_HIGH:
+            /* save pointer to buffer 1 */
+            D( "%s: AUDIO_SET_WRITE_BUFFER_1_HIGH %08x", __FUNCTION__, val);
+            goldfish_audio_buff_set_address_high( s->out_buff1, val );
+            break;
         case AUDIO_SET_WRITE_BUFFER_2:
             /* save pointer to buffer 2 */
             D( "%s: AUDIO_SET_WRITE_BUFFER_2 %08x", __FUNCTION__, val);
             goldfish_audio_buff_set_address( s->out_buff2, val );
             break;
+        case AUDIO_SET_WRITE_BUFFER_2_HIGH:
+            /* save pointer to buffer 2 */
+            D( "%s: AUDIO_SET_WRITE_BUFFER_2_HIGH %08x", __FUNCTION__, val);
+            goldfish_audio_buff_set_address_high( s->out_buff2, val );
+            break;
         case AUDIO_WRITE_BUFFER_1:
             /* record that data in buffer 1 is ready to write */
             //D( "%s: AUDIO_WRITE_BUFFER_1 %08x", __FUNCTION__, val);
@@ -462,6 +487,12 @@
             goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
             break;
 
+        case AUDIO_SET_READ_BUFFER_HIGH:
+            /* save pointer to the read buffer */
+            goldfish_audio_buff_set_address_high( s->in_buff, val );
+            D( "%s: AUDIO_SET_READ_BUFFER_HIGH %08x", __FUNCTION__, val );
+            break;
+
         default:
             cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset);
     }