commit fb076430b4deb94f05cb11dbb9c47b8a7061a011
Author: Wei Liu <liuw@liuw.name>
Date:   Tue Jul 19 16:15:15 2011 +0800

    Xen pv exec support.
    
    Basic support for QEMU to access Xen pv's address space.

diff --git a/Makefile.target b/Makefile.target
index c566eb1..b9df997 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -209,7 +209,7 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
 obj-$(CONFIG_NO_XEN) += xen-stub.o
 
-obj-i386-$(CONFIG_XEN) += xen_platform.o
+obj-i386-$(CONFIG_XEN) += xen_platform.o xen_exec.o
 
 # Inter-VM PCI shared memory
 CONFIG_IVSHMEM =
diff --git a/cpu-common.h b/cpu-common.h
index e1b40fe..a448f75 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -152,6 +152,20 @@ void stw_phys(target_phys_addr_t addr, uint32_t val);
 void stl_phys(target_phys_addr_t addr, uint32_t val);
 void stq_phys(target_phys_addr_t addr, uint64_t val);
 
+uint32_t ldub_xenpv(target_phys_addr_t addr);
+uint32_t lduw_xenpv(target_phys_addr_t addr);
+uint32_t ldl_xenpv(target_phys_addr_t addr);
+uint64_t ldq_xenpv(target_phys_addr_t addr);
+void stb_xenpv(target_phys_addr_t addr, uint32_t val);
+void stw_xenpv(target_phys_addr_t addr, uint32_t val);
+void stl_xenpv(target_phys_addr_t addr, uint32_t val);
+void stq_xenpv(target_phys_addr_t addr, uint64_t val);
+
+void *xenpv_map_iov(target_phys_addr_t addr,
+                    target_phys_addr_t *len,
+                    int is_write);
+void xenpv_unmap_iov(void *addr, target_phys_addr_t size);
+
 void cpu_physical_memory_write_rom(target_phys_addr_t addr,
                                    const uint8_t *buf, int len);
 
diff --git a/hw/xen_exec.c b/hw/xen_exec.c
new file mode 100644
index 0000000..26cbb2f
--- /dev/null
+++ b/hw/xen_exec.c
@@ -0,0 +1,209 @@
+#include "xen_backend.h"
+#include <xenctrl.h>
+#include <sys/mman.h>
+
+uint64_t ldq_xenpv(target_phys_addr_t addr)
+{
+    uint64_t ret;
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    ret = ldq_p(ptr);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+
+    return ret;
+}
+
+uint32_t ldl_xenpv(target_phys_addr_t addr)
+{
+    uint32_t ret;
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    ret = ldl_p(ptr);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+
+    return ret;
+}
+
+uint32_t lduw_xenpv(target_phys_addr_t addr)
+{
+    uint32_t ret;
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    ret = lduw_p(ptr);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+
+    return ret;
+}
+
+uint32_t ldub_xenpv(target_phys_addr_t addr)
+{
+    uint32_t ret;
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    ret = ldub_p(ptr);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+
+    return ret;
+}
+
+void stq_xenpv(target_phys_addr_t addr, uint64_t val)
+{
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ|PROT_WRITE,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    stq_p(ptr, val);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+}
+
+void stw_xenpv(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ|PROT_WRITE,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    stw_p(ptr, val);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+}
+
+void stl_xenpv(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ|PROT_WRITE,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    stl_p(ptr, val);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+}
+
+void stb_xenpv(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t *ptr;
+
+    /* Map this page -- one page only */
+    ptr = xc_map_foreign_range(xen_xc, xen_domid, 1, PROT_READ|PROT_WRITE,
+                               addr >> XC_PAGE_SHIFT);
+    if (!ptr) {
+        abort();
+    }
+
+    ptr += addr & ~XC_PAGE_MASK;
+    stb_p(ptr, val);
+    ptr -= addr & ~XC_PAGE_MASK;
+
+    munmap(ptr, XC_PAGE_SIZE);
+}
+
+void *xenpv_map_iov(target_phys_addr_t addr,
+                    target_phys_addr_t *len,
+                    int is_write)
+{
+    uint8_t *vaddr_base;
+    int prot = PROT_READ;
+    int size;
+    int offset;
+
+    if (*len < XC_PAGE_SIZE) {
+        size = 1;
+    } else if (*len % XC_PAGE_SIZE) {
+        size = (*len >> XC_PAGE_SHIFT) + 1;
+    } else {
+        size = *len >> XC_PAGE_SHIFT;
+    }
+
+    offset = addr & ~XC_PAGE_MASK;
+    addr >>= XC_PAGE_SHIFT;
+
+    prot |= is_write ? PROT_WRITE : 0;
+
+
+    vaddr_base = xc_map_foreign_range(xen_xc, xen_domid, size,
+                                      prot, addr);
+
+    if (!vaddr_base) {
+        perror("xenpv_iov_map");
+        exit(-1);
+    }
+
+    return vaddr_base + offset;
+}
+
+void xenpv_unmap_iov(void *addr, target_phys_addr_t size)
+{
+    unsigned long addr1 = (unsigned long)addr & XC_PAGE_MASK;
+
+    /* This 'size' passed in is the length of a iov. However, we are
+     * mapping page with xc_map_foreign_range, which works on page
+     * boundary. So round up the size if necessary. */
+    if (size < XC_PAGE_SIZE) {
+        size = XC_PAGE_SIZE;
+    } else if (size % XC_PAGE_SIZE) {
+        size = (size & XC_PAGE_MASK) + XC_PAGE_SIZE;
+    }
+
+    munmap((void *)addr1, size);
+}
