[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1446825115-23505-1-git-send-email-yalin.wang2010@gmail.com>
Date: Fri, 6 Nov 2015 23:51:55 +0800
From: yalin wang <yalin.wang2010@...il.com>
To: yalin.wang2010@...il.com, gregkh@...uxfoundation.org,
peter.senna@...il.com, joe@...ches.com, dan.carpenter@...cle.com,
linux-kernel@...r.kernel.org
Subject: [PATCH] goldfish: fix goldfish_pipe driver BUG
goldfish_pipe_read_write() should pass the buffer's physical
address to qemu, so that host can copy access data correctly,
currently, the drier write a virtual address into address register,
host can not get correct data, then adbd daemon can not work in guest.
Also I comment off access_with_param() function, seems not used,
we don't need use this function in goldfish_pipe_read_write().
Signed-off-by: yalin wang <yalin.wang2010@...il.com>
---
drivers/platform/goldfish/goldfish_pipe.c | 56 +++++++++++++++++++------------
1 file changed, 35 insertions(+), 21 deletions(-)
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 55b6d7c..bdf6f11 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -112,16 +112,27 @@
#define PIPE_WAKE_READ (1 << 1) /* pipe can now be read from */
#define PIPE_WAKE_WRITE (1 << 2) /* pipe can now be written to */
+#ifdef CONFIG_64BIT
struct access_params {
- unsigned long channel;
- u32 size;
- unsigned long address;
- u32 cmd;
- u32 result;
+ uint64_t channel; /* 0x00 */
+ uint32_t size; /* 0x08 */
+ uint64_t address; /* 0x0c */
+ uint32_t cmd; /* 0x14 */
+ uint32_t result; /* 0x18 */
/* reserved for future extension */
- u32 flags;
+ uint32_t flags; /* 0x1c */
};
-
+#else
+struct access_params {
+ uint32_t channel; /* 0x00 */
+ uint32_t size; /* 0x04 */
+ uint32_t address; /* 0x08 */
+ uint32_t cmd; /* 0x0c */
+ uint32_t result; /* 0x10 */
+ /* reserved for future extension */
+ uint32_t flags; /* 0x14 */
+};
+#endif
/* The global driver data. Holds a reference to the i/o page used to
* communicate with the emulator, and a wake queue for blocked tasks
* waiting to be awoken.
@@ -237,6 +248,7 @@ static int setup_access_params_addr(struct platform_device *pdev,
return -1;
}
+#if 0
/* A value that will not be set by qemu emulator */
#define INITIAL_BATCH_RESULT (0xdeadbeaf)
static int access_with_param(struct goldfish_pipe_dev *dev, const int cmd,
@@ -263,6 +275,7 @@ static int access_with_param(struct goldfish_pipe_dev *dev, const int cmd,
*status = aps->result;
return 0;
}
+#endif
/* This function is used for both reading from and writing to a given
* pipe.
@@ -304,6 +317,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
: address_end;
unsigned long avail = next - address;
int status, wakeBit;
+ struct page *page;
+ phys_addr_t phys_addr;
/* Ensure that the corresponding page is properly mapped */
/* FIXME: this isn't safe or sufficient - use get_user_pages */
@@ -323,23 +338,22 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
break;
}
}
-
+ if (get_user_pages_unlocked(current, current->active_mm,
+ address, 1, !is_write, 0, &page) != 1)
+ return -EINVAL;
+ phys_addr = page_to_phys(page) + offset_in_page(address);
/* Now, try to transfer the bytes in the current page */
spin_lock_irqsave(&dev->lock, irq_flags);
- if (access_with_param(dev, CMD_WRITE_BUFFER + cmd_offset,
- address, avail, pipe, &status)) {
- gf_write_ptr(pipe, dev->base + PIPE_REG_CHANNEL,
- dev->base + PIPE_REG_CHANNEL_HIGH);
- writel(avail, dev->base + PIPE_REG_SIZE);
- gf_write_ptr((void *)address,
- dev->base + PIPE_REG_ADDRESS,
- dev->base + PIPE_REG_ADDRESS_HIGH);
- writel(CMD_WRITE_BUFFER + cmd_offset,
- dev->base + PIPE_REG_COMMAND);
- status = readl(dev->base + PIPE_REG_STATUS);
- }
+ gf_write_ptr(pipe, dev->base + PIPE_REG_CHANNEL,
+ dev->base + PIPE_REG_CHANNEL_HIGH);
+ writel(avail, dev->base + PIPE_REG_SIZE);
+ gf_write_ptr((void *)phys_addr, dev->base + PIPE_REG_ADDRESS,
+ dev->base + PIPE_REG_ADDRESS_HIGH);
+ writel(CMD_WRITE_BUFFER + cmd_offset,
+ dev->base + PIPE_REG_COMMAND);
+ status = readl(dev->base + PIPE_REG_STATUS);
spin_unlock_irqrestore(&dev->lock, irq_flags);
-
+ put_page(page);
if (status > 0) { /* Correct transfer */
ret += status;
address += status;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists