aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Ning <yu.ning@intel.com>2015-02-02 22:36:50 +0800
committerYu Ning <yu.ning@intel.com>2015-02-03 15:52:41 +0800
commit10c79ce0959875f1f72b69c34f8df2e09f11adcc (patch)
tree96ed5ef0dbefa169f74dd49e0fc08bd9d5a4d502
parentc41beafed8b0b2dd50915f9cd8ef3467297183ee (diff)
downloadqemu-android-10c79ce0959875f1f72b69c34f8df2e09f11adcc.tar.gz
android_pipe: Use guest physical address for buffer read/write
For reading and writing guest user space buffers, currently the kernel sends the guest virtual address of the buffer to the pipe device. This virtual address has to be first converted to a guest physical address. Doing this translation on the QEMU side is inefficient and requires additional handling when KVM is enabled, whose implementation would either incur intrusive changes to QEMU's KVM support code or suffer from poor performance (see commit 08c7228 of $AOSP/external/qemu for details), and thus should be avoided if possible. There is a TODO comment on map_guest_buffer() (hw/misc/android_pipe.c) which requests that the translation be done on the kernel side and that physical addresses be passed to the device instead of virtual ones. This patch implements the QEMU-side changes. In order to allow the kernel to work with both the new (paddr-based) and the old (vaddr-based) pipe devices, a read-only register is added to the new device, which is read by the pipe driver to obtain the version of the device. The new pipe device is assigned a non-zero version number (currently 1), while the old device automatically gets version 0 because it simply returns 0 on read of any unknown register. This way, the driver can tell which version of the emulator is running on the host, and then sends either the virtual or the physical address for buffer read/write. See https://android-review.googlesource.com/127963 for the kernel-side patch. Change-Id: Icbc0bdc58b13219e380baea2097011225380e72c Signed-off-by: Yu Ning <yu.ning@intel.com>
-rw-r--r--hw/misc/android_pipe.c28
-rw-r--r--include/hw/misc/android_pipe.h1
2 files changed, 13 insertions, 16 deletions
diff --git a/hw/misc/android_pipe.c b/hw/misc/android_pipe.c
index 17a7a47bf3..a4f2ff7b46 100644
--- a/hw/misc/android_pipe.c
+++ b/hw/misc/android_pipe.c
@@ -1,5 +1,6 @@
/* Copyright (C) 2011 The Android Open Source Project
** Copyright (C) 2014 Linaro Limited
+** Copyright (C) 2015 Intel Corporation
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
@@ -470,29 +471,21 @@ struct PipeDevice {
uint64_t params_addr;
};
-/* Map the guest buffer specified by the guest vaddr 'address'.
+/* Update this version number if the device's interface changes. */
+#define PIPE_DEVICE_VERSION 1
+
+/* Map the guest buffer specified by the guest paddr 'phys'.
* 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).
+ * because the paddr 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)
+static void *map_guest_buffer(hwaddr phys, 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 */
@@ -556,7 +549,7 @@ pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
break;
case PIPE_CMD_READ_BUFFER: {
- /* Translate virtual address into physical one, into emulator memory. */
+ /* Translate guest physical address into emulator memory. */
AndroidPipeBuffer buffer;
buffer.data = map_guest_buffer(dev->address, dev->size, 1);
if (!buffer.data) {
@@ -573,7 +566,7 @@ pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
}
case PIPE_CMD_WRITE_BUFFER: {
- /* Translate virtual address into physical one, into emulator memory. */
+ /* Translate guest physical address into emulator memory. */
AndroidPipeBuffer buffer;
buffer.data = map_guest_buffer(dev->address, dev->size, 0);
if (!buffer.data) {
@@ -760,6 +753,9 @@ static uint64_t pipe_dev_read(void *opaque, hwaddr offset, unsigned size)
case PIPE_REG_PARAMS_ADDR_LOW:
return (uint32_t)(dev->params_addr & 0xFFFFFFFFUL);
+ case PIPE_REG_VERSION:
+ return PIPE_DEVICE_VERSION;
+
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register %" HWADDR_PRId
" (0x%" HWADDR_PRIx ")\n", __FUNCTION__, offset, offset);
diff --git a/include/hw/misc/android_pipe.h b/include/hw/misc/android_pipe.h
index 3fe630faa0..73cb24c729 100644
--- a/include/hw/misc/android_pipe.h
+++ b/include/hw/misc/android_pipe.h
@@ -161,6 +161,7 @@ extern void android_pipe_wake( void* hwpipe, unsigned flags );
#define PIPE_REG_PARAMS_ADDR_HIGH 0x1c
/* write: access with paremeter buffer */
#define PIPE_REG_ACCESS_PARAMS 0x20
+#define PIPE_REG_VERSION 0x24 /* read: device version */
#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 */