From: Anthony PERARD <anthony.per...@citrix.com>

This patch adds a new Xen device model target to Qemu, called
target-xen.
The new target makes use of the previously introduced xen_machine_fv.
In order to have a fully working Xen device model we still need
functionalities introduced by the following patches.

Signed-off-by: Anthony PERARD <anthony.per...@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabell...@eu.citrix.com>
---
 Makefile.target                    |   31 ++-
 arch_init.c                        |    2 +
 arch_init.h                        |    1 +
 configure                          |   11 +-
 default-configs/xen-dm-softmmu.mak |   24 ++
 target-xen/cpu.h                   |  116 ++++++
 target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |   63 +++
 target-xen/qemu-xen.h              |   30 ++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |   14 +
 11 files changed, 1120 insertions(+), 5 deletions(-)
 create mode 100644 default-configs/xen-dm-softmmu.mak
 create mode 100644 target-xen/cpu.h
 create mode 100644 target-xen/exec-dm.c
 create mode 100644 target-xen/helper.c
 create mode 100644 target-xen/machine.c
 create mode 100644 target-xen/qemu-xen.h
 create mode 100644 target-xen/stub-functions.c
 create mode 100644 target-xen/xen_mapcache.c

diff --git a/Makefile.target b/Makefile.target
index 8fdc884..359a984 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 
-# xen full virtualized machine
-obj-$(CONFIG_XEN) += xen_machine_fv.o
-
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
@@ -310,6 +307,34 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 
 endif # CONFIG_SOFTMMU
 
+# Xen Device Model
+# xen full virtualized machine
+
+# Remove some lib, because we don't want it for a xen target.
+ifeq ($(TARGET_BASE_ARCH), xen)
+bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
+bad-libobj-y += tcg%.o fpu/%.o
+bad-libobj-y += disas.o op_helper.o
+libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
+endif
+
+obj-xen-y += xen_machine_fv.o
+obj-xen-y += i8259.o
+obj-xen-y += pc.o
+obj-xen-y += piix_pci.o
+obj-xen-y += mc146818rtc.o
+
+obj-xen-y += xen_mapcache.o
+obj-xen-y += stub-functions.o
+
+obj-xen-y += vga.o
+obj-xen-y += hpet.o
+obj-xen-y += cirrus_vga.o
+obj-xen-y += smbios.o
+obj-xen-y += multiboot.o
+obj-xen-y += exec-dm.o
+obj-xen-y += lsi53c895a.o usb-ohci.o
+
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
diff --git a/arch_init.c b/arch_init.c
index 47bb4b2..ebc5cb6 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -75,6 +75,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR 
"/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_SH4
 #elif defined(TARGET_SPARC)
 #define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XEN)
+#define QEMU_ARCH QEMU_ARCH_XEN
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
diff --git a/arch_init.h b/arch_init.h
index 682890c..b5f8eb1 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -16,6 +16,7 @@ enum {
     QEMU_ARCH_S390X = 256,
     QEMU_ARCH_SH4 = 512,
     QEMU_ARCH_SPARC = 1024,
+    QEMU_ARCH_XEN = 2048,
 };
 
 extern const uint32_t arch_type;
diff --git a/configure b/configure
index 4c7c729..1ff6e80 100755
--- a/configure
+++ b/configure
@@ -2522,6 +2522,9 @@ case "$target" in
   ${target_arch2}-softmmu)
     target_softmmu="yes"
     ;;
+  ${target_arch2}-dm-softmmu)
+    target_softmmu="yes"
+    ;;
   ${target_arch2}-linux-user)
     if test "$linux" != "yes" ; then
       echo "ERROR: Target '$target' is only available on a Linux host"
@@ -2587,6 +2590,10 @@ case "$target_arch2" in
     TARGET_BASE_ARCH=i386
     target_phys_bits=64
   ;;
+  xen)
+    # This is use for xen mapcache
+    target_phys_bits=64
+  ;;
   alpha)
     target_phys_bits=64
     target_nptl="yes"
@@ -2698,7 +2705,7 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
 fi
 echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
 case "$target_arch2" in
-  i386|x86_64)
+  i386|x86_64|xen)
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
       echo "CONFIG_XEN=y" >> $config_target_mak
     fi
@@ -2864,7 +2871,7 @@ if test "$target_softmmu" = "yes" ; then
   arm)
     cflags="-DHAS_AUDIO $cflags"
   ;;
-  i386|mips|ppc)
+  i386|mips|ppc|xen)
     cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
   ;;
   esac
diff --git a/default-configs/xen-dm-softmmu.mak 
b/default-configs/xen-dm-softmmu.mak
new file mode 100644
index 0000000..72fe141
--- /dev/null
+++ b/default-configs/xen-dm-softmmu.mak
@@ -0,0 +1,24 @@
+# Default configuration for xen-dm-softmmu
+
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_USB_UHCI=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_IDE_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_PIIX_PCI=y
+CONFIG_SOUND=y
+CONFIG_XEN=y
diff --git a/target-xen/cpu.h b/target-xen/cpu.h
new file mode 100644
index 0000000..0e08ab3
--- /dev/null
+++ b/target-xen/cpu.h
@@ -0,0 +1,116 @@
+/*
+ * xen virtual CPU header
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_XEN_H
+#define CPU_XEN_H
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 64
+
+#ifdef TARGET_X86_64
+#define ELF_MACHINE     EM_X86_64
+#else
+#define ELF_MACHINE     EM_386
+#endif
+
+#define CPUState struct CPUXenState
+#define CPUX86State CPUXenState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+/* hidden flags - used internally by qemu to represent additional cpu
+   states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not
+   redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit
+   position to ease oring with eflags. */
+/* current cpl */
+#define HF_CPL_SHIFT         0
+#define HF_SMM_SHIFT        19 /* CPU in SMM mode */
+
+#define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
+#define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
+
+/* cpuid_features bits */
+#define CPUID_APIC (1 << 9)
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUXenState {
+    uint32_t hflags; /* TB flags, see HF_xxx constants. These flags
+                        are known at translation time. */
+    CPU_COMMON
+
+    /* processor features (e.g. for CPUID insn) */
+    uint32_t cpuid_features;
+    uint32_t cpuid_apic_id;
+
+    /* in order to simplify APIC support, we leave this pointer to the
+       user */
+    struct DeviceState *apic_state;
+} CPUXenState;
+
+CPUXenState *cpu_xen_init(const char *cpu_model);
+int cpu_xen_exec(CPUXenState *s);
+
+int cpu_get_pic_interrupt(CPUXenState *s);
+void cpu_set_ferr(CPUX86State *s);
+
+/* helper.c */
+void cpu_x86_set_a20(CPUXenState *env, int a20_state);
+
+/* hw/pc.c */
+void cpu_smm_update(CPUXenState *env);
+uint64_t cpu_get_tsc(CPUX86State *env);
+
+#define TARGET_PAGE_BITS 12
+
+#ifdef TARGET_X86_64
+#define TARGET_PHYS_ADDR_SPACE_BITS 52
+/* ??? This is really 48 bits, sign-extended, but the only thing
+   accessible to userland with bit 48 set is the VSYSCALL, and that
+   is handled via other mechanisms.  */
+#define TARGET_VIRT_ADDR_SPACE_BITS 47
+#else
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
+
+#define cpu_init cpu_xen_init
+#define cpu_exec cpu_xen_exec
+
+/* MMU modes definitions */
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+}
+
+#endif /* CPU_XEN_H */
diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c
new file mode 100644
index 0000000..5af6330
--- /dev/null
+++ b/target-xen/exec-dm.c
@@ -0,0 +1,791 @@
+/*
+ *  virtual page mapping and translated block handling
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "config.h"
+
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "disas.h"
+#include "hw/xen_common.h"
+#include "qemu-xen.h"
+#include "hw/xen.h"
+#include "hw/xen_backend.h"
+
+int use_icount = 0;
+int64_t qemu_icount;
+
+RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
+
+CPUState *first_cpu;
+/* current CPU in the current thread. It is only valid inside
+   cpu_exec() */
+CPUState *cpu_single_env;
+
+/* io memory support */
+CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
+CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+static int io_mem_nb = 1;
+
+/* log support */
+FILE *logfile;
+int loglevel;
+
+void cpu_exec_init_all(unsigned long tb_size)
+{
+}
+
+void cpu_exec_init(CPUState *env)
+{
+    CPUState **penv;
+    int cpu_index;
+
+    env->next_cpu = NULL;
+    penv = &first_cpu;
+    cpu_index = 0;
+    while (*penv != NULL) {
+        penv = (CPUState **)&(*penv)->next_cpu;
+        cpu_index++;
+    }
+    env->cpu_index = cpu_index;
+    *penv = env;
+}
+
+/* enable or disable low levels log */
+void cpu_set_log(int log_flags)
+{
+    loglevel = log_flags;
+    if (!logfile) {
+        logfile = stderr;
+    }
+}
+
+void cpu_set_log_filename(const char *filename)
+{
+    logfile = fopen(filename, "w");
+    if (!logfile) {
+        perror(filename);
+        _exit(1);
+    }
+#if !defined(CONFIG_SOFTMMU)
+    /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
+    {
+        static uint8_t logfile_buf[4096];
+        setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
+    }
+#else
+    setvbuf(logfile, NULL, _IOLBF, 0);
+#endif
+    dup2(fileno(logfile), 1);
+    dup2(fileno(logfile), 2);
+}
+
+/* mask must never be zero, except for A20 change call */
+void cpu_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+}
+
+void cpu_reset_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request &= ~mask;
+}
+
+const CPULogItem cpu_log_items[] = {
+#ifdef DEBUG_IOPORT
+    { CPU_LOG_IOPORT, "ioport",
+      "show all i/o ports accesses" },
+#endif
+    { 0, NULL, NULL },
+};
+
+static int cmp1(const char *s1, int n, const char *s2)
+{
+    if (strlen(s2) != n)
+        return 0;
+    return memcmp(s1, s2, n) == 0;
+}
+
+/* takes a comma separated list of log masks. Return 0 if error. */
+int cpu_str_to_log_mask(const char *str)
+{
+    const CPULogItem *item;
+    int mask;
+    const char *p, *p1;
+
+    p = str;
+    mask = 0;
+    for(;;) {
+        p1 = strchr(p, ',');
+        if (!p1) {
+            p1 = p + strlen(p);
+        }
+        if(cmp1(p,p1-p,"all")) {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                mask |= item->mask;
+            }
+        } else {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                if (cmp1(p, p1 - p, item->name))
+                    goto found;
+            }
+            return 0;
+        }
+found:
+        mask |= item->mask;
+        if (*p1 != ',')
+            break;
+        p = p1 + 1;
+    }
+    return mask;
+}
+
+/* XXX: Simple implementation. Fix later */
+#define MAX_MMIO 1024
+static struct MMIOSpace {
+    target_phys_addr_t start;
+    unsigned long size;
+    unsigned long io_index;
+} mmio[MAX_MMIO];
+static unsigned long mmio_cnt;
+
+/* register physical memory. 'size' must be a multiple of the target
+   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
+   io memory page */
+void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+                                         ram_addr_t size,
+                                         ram_addr_t phys_offset,
+                                         ram_addr_t region_offset)
+{
+    region_offset &= TARGET_PAGE_MASK;
+    start_addr += region_offset;
+
+    int i;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        if(mmio[i].start == start_addr) {
+            mmio[i].io_index = phys_offset;
+            mmio[i].size = size;
+            return;
+        }
+    }
+
+    if (mmio_cnt == MAX_MMIO) {
+        fprintf(stderr, "too many mmio regions\n");
+        exit(-1);
+    }
+
+    mmio[mmio_cnt].io_index = phys_offset;
+    mmio[mmio_cnt].start = start_addr;
+    mmio[mmio_cnt++].size = size;
+}
+
+/* mem_read and mem_write are arrays of functions containing the
+   function to access byte (index 0), word (index 1) and dword (index
+   2). All functions must be supplied. If io_index is non zero, the
+   corresponding io zone is modified. If it is zero, a new io zone is
+   allocated. The return value can be used with
+   cpu_register_physical_memory(). (-1) is returned if error. */
+int cpu_register_io_memory_fixed(int io_index,
+                           CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque)
+{
+    int i;
+
+    if (io_index <= 0) {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+        io_index = io_mem_nb++;
+    } else {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
+
+    for(i = 0;i < 3; i++) {
+        io_mem_read[io_index][i] = mem_read[i];
+        io_mem_write[io_index][i] = mem_write[i];
+    }
+    io_mem_opaque[io_index] = opaque;
+    return io_index << IO_MEM_SHIFT;
+}
+
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque)
+{
+    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
+}
+
+void cpu_unregister_io_memory(int io_table_address)
+{
+    int i;
+    int io_index = io_table_address >> IO_MEM_SHIFT;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        if (mmio[i].size && mmio[i].io_index == io_index) {
+            mmio[i].start = mmio[i].size = 0;
+            break;
+        }
+    }
+
+    for (i=0;i < 3; i++) {
+        io_mem_read[io_index][i] = NULL;
+        io_mem_write[io_index][i] = NULL;
+    }
+    io_mem_opaque[io_index] = NULL;
+}
+
+int cpu_physical_memory_set_dirty_tracking(int enable)
+{
+    return 0;
+}
+
+#ifdef __ia64__
+
+#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_sync_i()   asm volatile (";; sync.i" ::: "memory")
+#define ia64_srlz_i()   asm volatile (";; srlz.i ;;" ::: "memory")
+
+/* IA64 has seperate I/D cache, with coherence maintained by DMA controller.
+ * So to emulate right behavior that guest OS is assumed, we need to flush
+ * I/D cache here.
+ */
+static void sync_icache(uint8_t *address, int len)
+{
+    unsigned long addr = (unsigned long)address;
+    unsigned long end = addr + len;
+
+    for (addr &= ~(32UL-1); addr < end; addr += 32UL) {
+        __ia64_fc(addr);
+    }
+
+    ia64_sync_i();
+    ia64_srlz_i();
+}
+#endif
+
+static int iomem_index(target_phys_addr_t addr)
+{
+    int i;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        unsigned long start, end;
+
+        start = mmio[i].start;
+        end = mmio[i].start + mmio[i].size;
+
+        if ((addr >= start) && (addr < end)) {
+            return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 
1);
+        }
+    }
+    return 0;
+}
+
+unsigned int xen_logdirty_enable = 0;
+
+/*
+ * Replace the standard byte memcpy with a word memcpy for appropriately sized
+ * memory copy operations.  Some users (USB-UHCI) can not tolerate the possible
+ * word tearing that can result from a guest concurrently writing a memory
+ * structure while the qemu device model is modifying the same location.
+ * Forcing a word-sized read/write prevents the guest from seeing a partially
+ * written word-sized atom.
+ */
+#if defined(__x86_64__) || defined(__i386__)
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+    asm volatile (
+        "   movl %%edx,%%ecx \n"
+#ifdef __x86_64__
+        "   shrl $3,%%ecx    \n"
+        "   rep  movsq       \n"
+        "   test $4,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsl            \n"
+#else /* __i386__ */
+        "   shrl $2,%%ecx    \n"
+        "   rep  movsl       \n"
+#endif
+        "1: test $2,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsw            \n"
+        "1: test $1,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsb            \n"
+        "1:                  \n"
+        : "+S" (src), "+D" (dst) : "d" (n) : "ecx", "memory" );
+}
+#else
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+    /* Some architectures do not like unaligned accesses. */
+    if (((unsigned long)dst | (unsigned long)src) & 3) {
+        memcpy(dst, src, n);
+        return;
+    }
+
+    while (n >= sizeof(uint32_t)) {
+        *((uint32_t *)dst) = *((uint32_t *)src);
+        dst = ((uint32_t *)dst) + 1;
+        src = ((uint32_t *)src) + 1;
+        n -= sizeof(uint32_t);
+    }
+
+    if (n & 2) {
+        *((uint16_t *)dst) = *((uint16_t *)src);
+        dst = ((uint16_t *)dst) + 1;
+        src = ((uint16_t *)src) + 1;
+    }
+
+    if (n & 1) {
+        *((uint8_t *)dst) = *((uint8_t *)src);
+        dst = ((uint8_t *)dst) + 1;
+        src = ((uint8_t *)src) + 1;
+    }
+}
+#endif
+
+void cpu_physical_memory_rw(target_phys_addr_t _addr, uint8_t *buf,
+                            int _len, int is_write)
+{
+    target_phys_addr_t addr = _addr;
+    int len = _len;
+    int l, io_index;
+    uint8_t *ptr;
+    uint32_t val;
+
+    mapcache_lock();
+
+    while (len > 0) {
+        /* How much can we copy before the next page boundary? */
+        l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK);
+        if (l > len) {
+            l = len;
+        }
+
+        io_index = iomem_index(addr);
+        if (is_write) {
+            if (io_index) {
+                if (l >= 4 && ((addr & 3) == 0)) {
+                    /* 32 bit read access */
+                    val = ldl_raw(buf);
+                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr, 
val);
+                    l = 4;
+                } else if (l >= 2 && ((addr & 1) == 0)) {
+                    /* 16 bit read access */
+                    val = lduw_raw(buf);
+                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr, 
val);
+                    l = 2;
+                } else {
+                    /* 8 bit access */
+                    val = ldub_raw(buf);
+                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr, 
val);
+                    l = 1;
+                }
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+                /* Writing to RAM */
+                memcpy_words(ptr, buf, l);
+
+                if (xen_logdirty_enable) {
+                    xc_hvm_modified_memory(xen_xc,
+                            xen_domid,
+                            addr >> TARGET_PAGE_BITS,
+                            ((addr + l + TARGET_PAGE_SIZE - 1) >> 
TARGET_PAGE_BITS)
+                            - (addr >> TARGET_PAGE_BITS));
+                }
+#ifdef __ia64__
+                sync_icache(ptr, l);
+#endif
+            }
+        } else {
+            if (io_index) {
+                if (l >= 4 && ((addr & 3) == 0)) {
+                    /* 32 bit read access */
+                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], 
addr);
+                    stl_raw(buf, val);
+                    l = 4;
+                } else if (l >= 2 && ((addr & 1) == 0)) {
+                    /* 16 bit read access */
+                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], 
addr);
+                    stw_raw(buf, val);
+                    l = 2;
+                } else {
+                    /* 8 bit access */
+                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], 
addr);
+                    stb_raw(buf, val);
+                    l = 1;
+                }
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+                /* Reading from RAM */
+                memcpy_words(buf, ptr, l);
+            } else {
+                /* Neither RAM nor known MMIO space */
+                memset(buf, 0xff, len);
+            }
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+
+    mapcache_unlock();
+}
+
+/* virtual memory access for debug */
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+                        uint8_t *buf, int len, int is_write)
+{
+    int l;
+    target_ulong page, phys_addr;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        phys_addr = cpu_get_phys_page_debug(env, page);
+        /* if no physical page mapped, return an error */
+        if (phys_addr == -1)
+            return -1;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
+                               buf, l, is_write);
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+    return 0;
+}
+
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+                                     int dirty_flags)
+{
+    unsigned long length;
+    int i, mask, len;
+    uint8_t *p;
+
+    start &= TARGET_PAGE_MASK;
+    end = TARGET_PAGE_ALIGN(end);
+
+    length = end - start;
+    if (length == 0)
+        return;
+    mask = ~dirty_flags;
+    p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+    len = length >> TARGET_PAGE_BITS;
+    for(i = 0; i < len; i++) {
+        p[i] &= mask;
+    }
+
+    return;
+}
+
+
+/* Unoptimised in Xen DM, nicked from git
+ *  aab33094073678d459ccaac5c60ea7533e8d1d8e */
+uint32_t ldub_phys(target_phys_addr_t addr)
+{
+    uint8_t val;
+    cpu_physical_memory_read(addr, &val, 1);
+    return val;
+}
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+    uint16_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
+    return tswap16(val);
+}
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+    uint64_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 8);
+    return tswap64(val);
+}
+void stb_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t v = val;
+    cpu_physical_memory_write(addr, &v, 1);
+}
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint16_t v = tswap16(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
+}
+void stq_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = tswap64(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
+}
+
+/* stubs which we hope (think!) are OK for Xen DM */
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+    val = tswap32(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, 4);
+}
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys(addr, val);
+}
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+    uint32_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 4);
+    return tswap32(val);
+}
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+                                   const uint8_t *buf, int len)
+{
+    return cpu_physical_memory_write(addr,buf,len);
+}
+
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+
+/* stub out various functions for Xen DM */
+void dump_exec_info(FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+}
+
+void monitor_disas(Monitor *mon, CPUState *env,
+                   target_ulong pc, int nb_insn, int is_physical, int flags)
+{
+}
+
+/*
+ * This next section was clone-and-hacked from the version in exec.c
+ * :-(.  But the exec.c version is full of tcg-specific stuff and
+ * assumptions about phys_ram_base.
+ */
+
+typedef struct MapClient {
+    void *opaque;
+    void (*callback)(void *opaque);
+    QLIST_ENTRY(MapClient) link;
+} MapClient;
+
+static QLIST_HEAD(map_client_list, MapClient) map_client_list
+    = QLIST_HEAD_INITIALIZER(map_client_list);
+
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+{
+    MapClient *client = qemu_malloc(sizeof(*client));
+
+    client->opaque = opaque;
+    client->callback = callback;
+    QLIST_INSERT_HEAD(&map_client_list, client, link);
+    return client;
+}
+
+void cpu_unregister_map_client(void *_client)
+{
+    MapClient *client = (MapClient *)_client;
+
+    QLIST_REMOVE(client, link);
+    qemu_free(client);
+}
+
+static void cpu_notify_map_clients(void)
+{
+    MapClient *client;
+
+    while (!QLIST_EMPTY(&map_client_list)) {
+        client = QLIST_FIRST(&map_client_list);
+        client->callback(client->opaque);
+        cpu_unregister_map_client(client);
+    }
+}
+
+/* Map a physical memory region into a host virtual address.
+ * May map a subset of the requested range, given by and returned in *plen.
+ * May return NULL if resources needed to perform the mapping are exhausted.
+ * Use only for reads OR writes - not for read-modify-write operations.
+ * Use cpu_register_map_client() to know when retrying the map operation is
+ * likely to succeed.
+ */
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+                              target_phys_addr_t *plen,
+                              int is_write)
+{
+    unsigned long l = 0;
+#ifdef MAPCACHE
+    l = MCACHE_BUCKET_SIZE - (addr & (MCACHE_BUCKET_SIZE-1));
+    if ((*plen) > l) {
+        *plen = l;
+    }
+#endif
+    if (xen_logdirty_enable) {
+        xc_hvm_modified_memory(xen_xc, xen_domid, addr >> TARGET_PAGE_BITS,
+                ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+                    - (addr >> TARGET_PAGE_BITS));
+    }
+
+    return qemu_map_cache(addr, 1);
+}
+
+/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
+ * Will also mark the memory as dirty if is_write == 1.  access_len gives
+ * the amount of memory that was actually read or written by the caller.
+ */
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+                               int is_write, target_phys_addr_t access_len)
+{
+    qemu_invalidate_entry(buffer);
+    cpu_notify_map_clients();
+}
+
+
+void cpu_exit(CPUState *env)
+{
+    env->exit_request = 1;
+}
+
+void qemu_flush_coalesced_mmio_buffer(void)
+{
+}
+
+void *qemu_get_ram_ptr(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr - block->offset < block->length) {
+            QLIST_REMOVE(block, next);
+            QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
+            return block->host + (addr - block->offset);
+        }
+    }
+    return block->host + (addr - block->offset);
+
+    fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+    abort();
+
+    return NULL;
+}
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr)
+{
+    return 0;
+}
+ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static ram_addr_t find_ram_offset(ram_addr_t size)
+{
+    RAMBlock *block;
+    ram_addr_t last = 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        last = MAX(last, block->offset + block->length);
+    }
+
+    return last;
+}
+
+ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
+{
+    RAMBlock *new_block;
+
+    size = TARGET_PAGE_ALIGN(size);
+    new_block = qemu_malloc(sizeof(*new_block));
+
+    if (mem_path) {
+#if defined (__linux__) && !defined(TARGET_S390X)
+        new_block->host = 0; // file_ram_alloc(size, mem_path);
+        if (!new_block->host) {
+            new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+            madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+        }
+#else
+        fprintf(stderr, "-mem-path option unsupported\n");
+        exit(1);
+#endif
+    } else {
+        new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+        madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+    }
+    new_block->offset = find_ram_offset(size);
+    new_block->length = size;
+
+    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+    ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+        (new_block->offset + size) >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0xff, size >> TARGET_PAGE_BITS);
+
+    return new_block->offset;
+}
+
+void qemu_ram_free(ram_addr_t addr)
+{
+}
+
+void tb_flush(CPUState *env1)
+{
+}
+
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint)
+{
+    return -ENOSYS;
+}
+
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags)
+{
+    return -ENOENT;
+}
+
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint)
+{
+    return -ENOSYS;
+}
+
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
+{
+    return -ENOSYS;
+}
+
+void cpu_breakpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+void cpu_single_step(CPUState *env, int enabled)
+{
+}
diff --git a/target-xen/helper.c b/target-xen/helper.c
new file mode 100644
index 0000000..f8512c8
--- /dev/null
+++ b/target-xen/helper.c
@@ -0,0 +1,63 @@
+/*
+ *  i386 helpers (without register variable usage)
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "cpu.h"
+
+CPUXenState *cpu_xen_init(const char *cpu_model)
+{
+    CPUXenState *env = NULL;
+    static int inited;
+
+    env = qemu_mallocz(sizeof(CPUXenState));
+    cpu_exec_init(env);
+
+    /* init various static tables */
+    if (!inited) {
+        inited = 1;
+
+        cpu_single_env = env;
+    }
+
+    return env;
+}
+
+int cpu_xen_exec(CPUState *env1)
+{
+    return 0;
+}
+
+void cpu_reset(CPUXenState *env)
+{
+}
+
+void cpu_dump_state(CPUState *env, FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags)
+{
+}
+
+void cpu_x86_set_a20(CPUXenState *env, int a20_state)
+{
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr;
+}
diff --git a/target-xen/machine.c b/target-xen/machine.c
new file mode 100644
index 0000000..e69de29
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
new file mode 100644
index 0000000..d1910d6
--- /dev/null
+++ b/target-xen/qemu-xen.h
@@ -0,0 +1,30 @@
+#ifndef QEMU_XEN_H
+#define QEMU_XEN_H
+
+#include "hw/xen_common.h"
+
+/* vl.c */
+
+#if defined(__i386__) || defined(__x86_64__)
+#define phys_ram_addr(x) (qemu_map_cache(x, 0))
+#elif defined(__ia64__)
+#define phys_ram_addr(x) (((x) < ram_size) ? (phys_ram_base + (x)) : NULL)
+#endif
+
+/* xen_mapcache.c */
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock);
+void     qemu_invalidate_entry(uint8_t *buffer);
+void     qemu_invalidate_map_cache(void);
+
+#define mapcache_lock()   ((void)0)
+#define mapcache_unlock() ((void)0)
+
+/* target-xen/exec-dm.c */
+
+int cpu_register_io_memory_fixed(int io_index,
+                           CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque);
+
+#endif /*QEMU_XEN_H*/
diff --git a/target-xen/stub-functions.c b/target-xen/stub-functions.c
new file mode 100644
index 0000000..0db6898
--- /dev/null
+++ b/target-xen/stub-functions.c
@@ -0,0 +1,42 @@
+#include "config.h"
+#include "disas.h"
+#include "hw/apic.h"
+#include "hw/pc.h"
+#include "cpu.h"
+
+/* disas */
+struct syminfo *syminfos = NULL;
+
+/* apic */
+void apic_deliver_pic_intr(DeviceState *d, int level)
+{
+}
+
+int apic_get_interrupt(DeviceState *d)
+{
+    return -1;
+}
+
+int apic_accept_pic_intr(DeviceState *d)
+{
+    return 0;
+}
+
+/* vmmouse */
+void *vmmouse_init(void *m)
+{
+    return NULL;
+}
+
+/* cpu-exec */
+volatile sig_atomic_t exit_request;
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+{
+    return NULL;
+}
+
+int qemu_cpu_has_work(CPUState *env)
+{
+    return 0;
+}
diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c
new file mode 100644
index 0000000..39daae2
--- /dev/null
+++ b/target-xen/xen_mapcache.c
@@ -0,0 +1,14 @@
+#include "qemu-xen.h"
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
+{
+    return phys_ram_addr(phys_addr);
+}
+
+void qemu_invalidate_map_cache(void)
+{
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+}
-- 
1.7.0.4


Reply via email to