|
@@ -382,6 +382,9 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
|
|
vaddr l, page;
|
|
|
void * p;
|
|
|
uint8_t *buf = ptr;
|
|
|
+ ssize_t written;
|
|
|
+ int ret = -1;
|
|
|
+ int fd = -1;
|
|
|
|
|
|
while (len > 0) {
|
|
|
page = addr & TARGET_PAGE_MASK;
|
|
@@ -389,30 +392,75 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
|
|
if (l > len)
|
|
|
l = len;
|
|
|
flags = page_get_flags(page);
|
|
|
- if (!(flags & PAGE_VALID))
|
|
|
- return -1;
|
|
|
+ if (!(flags & PAGE_VALID)) {
|
|
|
+ goto out_close;
|
|
|
+ }
|
|
|
if (is_write) {
|
|
|
- if (!(flags & PAGE_WRITE))
|
|
|
- return -1;
|
|
|
- /* XXX: this code should not depend on lock_user */
|
|
|
- if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
|
|
|
- return -1;
|
|
|
- memcpy(p, buf, l);
|
|
|
- unlock_user(p, addr, l);
|
|
|
- } else {
|
|
|
- if (!(flags & PAGE_READ))
|
|
|
- return -1;
|
|
|
+ if (flags & PAGE_WRITE) {
|
|
|
+ /* XXX: this code should not depend on lock_user */
|
|
|
+ p = lock_user(VERIFY_WRITE, addr, l, 0);
|
|
|
+ if (!p) {
|
|
|
+ goto out_close;
|
|
|
+ }
|
|
|
+ memcpy(p, buf, l);
|
|
|
+ unlock_user(p, addr, l);
|
|
|
+ } else {
|
|
|
+ /* Bypass the host page protection using ptrace. */
|
|
|
+ if (fd == -1) {
|
|
|
+ fd = open("/proc/self/mem", O_WRONLY);
|
|
|
+ if (fd == -1) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * If there is a TranslationBlock and we weren't bypassing the
|
|
|
+ * host page protection, the memcpy() above would SEGV,
|
|
|
+ * ultimately leading to page_unprotect(). So invalidate the
|
|
|
+ * translations manually. Both invalidation and pwrite() must
|
|
|
+ * be under mmap_lock() in order to prevent the creation of
|
|
|
+ * another TranslationBlock in between.
|
|
|
+ */
|
|
|
+ mmap_lock();
|
|
|
+ tb_invalidate_phys_range(addr, addr + l - 1);
|
|
|
+ written = pwrite(fd, buf, l,
|
|
|
+ (off_t)(uintptr_t)g2h_untagged(addr));
|
|
|
+ mmap_unlock();
|
|
|
+ if (written != l) {
|
|
|
+ goto out_close;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (flags & PAGE_READ) {
|
|
|
/* XXX: this code should not depend on lock_user */
|
|
|
- if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
|
|
|
- return -1;
|
|
|
+ p = lock_user(VERIFY_READ, addr, l, 1);
|
|
|
+ if (!p) {
|
|
|
+ goto out_close;
|
|
|
+ }
|
|
|
memcpy(buf, p, l);
|
|
|
unlock_user(p, addr, 0);
|
|
|
+ } else {
|
|
|
+ /* Bypass the host page protection using ptrace. */
|
|
|
+ if (fd == -1) {
|
|
|
+ fd = open("/proc/self/mem", O_RDONLY);
|
|
|
+ if (fd == -1) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (pread(fd, buf, l,
|
|
|
+ (off_t)(uintptr_t)g2h_untagged(addr)) != l) {
|
|
|
+ goto out_close;
|
|
|
+ }
|
|
|
}
|
|
|
len -= l;
|
|
|
buf += l;
|
|
|
addr += l;
|
|
|
}
|
|
|
- return 0;
|
|
|
+ ret = 0;
|
|
|
+out_close:
|
|
|
+ if (fd != -1) {
|
|
|
+ close(fd);
|
|
|
+ }
|
|
|
+out:
|
|
|
+ return ret;
|
|
|
}
|
|
|
#endif
|
|
|
|