summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS5
-rw-r--r--Makefile36
-rw-r--r--arch_init.c5
-rw-r--r--compiler.h17
-rwxr-xr-xconfigure22
-rw-r--r--host-utils.h2
-rw-r--r--hw/adlib.c5
-rw-r--r--hw/cirrus_vga.c4
-rw-r--r--hw/e1000.c2
-rw-r--r--hw/irq.c14
-rw-r--r--hw/irq.h5
-rw-r--r--hw/pc.c8
-rw-r--r--hw/pc.h2
-rw-r--r--hw/pc_piix.c14
-rw-r--r--hw/qdev-properties.c2
-rw-r--r--hw/vga-isa.c1
-rw-r--r--hw/virtio.c14
-rw-r--r--linux-user/elfload.c56
-rw-r--r--linux-user/main.c674
-rw-r--r--linux-user/qemu.h6
-rw-r--r--linux-user/syscall.c63
-rw-r--r--osdep.h7
-rw-r--r--qemu-barrier.h34
-rw-r--r--qemu-char.c14
-rw-r--r--qemu-common.h3
-rw-r--r--qemu-tool.c4
-rw-r--r--target-ppc/kvm_ppc.c2
27 files changed, 684 insertions, 337 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 5046dc954a..2b4c5d727e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -62,6 +62,7 @@ F: target-alpha/
 
 ARM
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: target-arm/
 
@@ -168,6 +169,7 @@ F: hw/gumstix.c
 
 Integrator CP
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/integratorcp.c
 
@@ -193,6 +195,7 @@ F: hw/palm.c
 
 Real View
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/realview*
 
@@ -203,11 +206,13 @@ F: hw/spitz.c
 
 Stellaris
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/stellaris.c
 
 Versatile PB
 M: Paul Brook <paul@codesourcery.com>
+M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/versatilepb.c
 
diff --git a/Makefile b/Makefile
index a211158e2d..6ed3194fd7 100644
--- a/Makefile
+++ b/Makefile
@@ -368,41 +368,5 @@ tar:
 	cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn
 	rm -rf /tmp/$(FILE)
 
-SYSTEM_TARGETS=$(filter %-softmmu,$(TARGET_DIRS))
-SYSTEM_PROGS=$(patsubst %-softmmu,qemu-system-%, \
-             $(SYSTEM_TARGETS))
-
-USER_TARGETS=$(filter %-user,$(TARGET_DIRS))
-USER_PROGS=$(patsubst %-bsd-user,qemu-%, \
-           $(patsubst %-darwin-user,qemu-%, \
-           $(patsubst %-linux-user,qemu-%, \
-           $(USER_TARGETS))))
-
-# generate a binary distribution
-tarbin:
-	cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
-	$(patsubst %,$(bindir)/%, $(SYSTEM_PROGS)) \
-	$(patsubst %,$(bindir)/%, $(USER_PROGS)) \
-	$(bindir)/qemu-img \
-	$(bindir)/qemu-nbd \
-	$(datadir)/bios.bin \
-	$(datadir)/vgabios.bin \
-	$(datadir)/vgabios-cirrus.bin \
-	$(datadir)/ppc_rom.bin \
-	$(datadir)/openbios-sparc32 \
-	$(datadir)/openbios-sparc64 \
-	$(datadir)/openbios-ppc \
-	$(datadir)/pxe-e1000.rom \
-	$(datadir)/pxe-eepro100.rom \
-	$(datadir)/pxe-ne2k_pci.rom \
-	$(datadir)/pxe-pcnet.rom \
-	$(datadir)/pxe-rtl8139.rom \
-	$(datadir)/pxe-virtio.rom \
-	$(docdir)/qemu-doc.html \
-	$(docdir)/qemu-tech.html \
-	$(mandir)/man1/qemu.1 \
-	$(mandir)/man1/qemu-img.1 \
-	$(mandir)/man8/qemu-nbd.8
-
 # Include automatically generated dependency files
 -include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d)
diff --git a/arch_init.c b/arch_init.c
index 9a5a0e31b3..a6c69c75a9 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -459,11 +459,6 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-void qemu_service_io(void)
-{
-    qemu_notify_event();
-}
-
 #ifdef HAS_AUDIO
 struct soundhw {
     const char *name;
diff --git a/compiler.h b/compiler.h
index a2d5959e4b..a1c0794947 100644
--- a/compiler.h
+++ b/compiler.h
@@ -5,8 +5,20 @@
 
 #include "config-host.h"
 
+/*----------------------------------------------------------------------------
+| The macro QEMU_GNUC_PREREQ tests for minimum version of the GNU C compiler.
+| The code is a copy of SOFTFLOAT_GNUC_PREREQ, see softfloat-macros.h.
+*----------------------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define QEMU_GNUC_PREREQ(maj, min) \
+         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define QEMU_GNUC_PREREQ(maj, min) 0
+#endif
+
 #define QEMU_NORETURN __attribute__ ((__noreturn__))
-#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
+
+#if QEMU_GNUC_PREREQ(3, 4)
 #define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
 #else
 #define QEMU_WARN_UNUSED_RESULT
@@ -22,8 +34,7 @@
     typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1];
 
 #if defined __GNUC__
-# if (__GNUC__ < 4) || \
-     defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 4)
+# if !QEMU_GNUC_PREREQ(4, 4)
    /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */
 #  define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2)))
 #  define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m)))
diff --git a/configure b/configure
index 9ab3ab4eb0..24b8df4385 100755
--- a/configure
+++ b/configure
@@ -2359,23 +2359,6 @@ if compile_prog "" "" ; then
     need_offsetof=no
 fi
 
-##########################################
-# check if the compiler understands attribute warn_unused_result
-#
-# This could be smarter, but gcc -Werror does not error out even when warning
-# about attribute warn_unused_result
-
-gcc_attribute_warn_unused_result=no
-cat > $TMPC << EOF
-#if defined(__GNUC__) && (__GNUC__ < 4) && defined(__GNUC_MINOR__) && (__GNUC__ < 4)
-#error gcc 3.3 or older
-#endif
-int main(void) { return 0;}
-EOF
-if compile_prog "" ""; then
-    gcc_attribute_warn_unused_result=yes
-fi
-
 # spice probe
 if test "$spice" != "no" ; then
   cat > $TMPC << EOF
@@ -2998,9 +2981,6 @@ fi
 if test "$need_offsetof" = "yes" ; then
   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
 fi
-if test "$gcc_attribute_warn_unused_result" = "yes" ; then
-  echo "CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT=y" >> $config_host_mak
-fi
 if test "$fdatasync" = "yes" ; then
   echo "CONFIG_FDATASYNC=y" >> $config_host_mak
 fi
@@ -3622,7 +3602,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
 DIRS="$DIRS pc-bios/spapr-rtas"
 DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS fsdev ui"
-DIRS="$DIRS qapi"
+DIRS="$DIRS qapi qapi-generated"
 DIRS="$DIRS qga trace"
 FILES="Makefile tests/Makefile qdict-test-data.txt"
 FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
diff --git a/host-utils.h b/host-utils.h
index 0ddc176582..821db93671 100644
--- a/host-utils.h
+++ b/host-utils.h
@@ -23,7 +23,7 @@
  * THE SOFTWARE.
  */
 
-#include "osdep.h"
+#include "compiler.h"   /* QEMU_GNUC_PREREQ */
 
 #if defined(__x86_64__)
 #define __HAVE_FAST_MULU64__
diff --git a/hw/adlib.c b/hw/adlib.c
index c1c46e3573..e4bfcc6420 100644
--- a/hw/adlib.c
+++ b/hw/adlib.c
@@ -119,7 +119,6 @@ static IO_WRITE_PROTO (adlib_write)
 {
     AdlibState *s = opaque;
     int a = nport & 3;
-    int status;
 
     s->active = 1;
     AUD_set_active_out (s->voice, 1);
@@ -127,9 +126,9 @@ static IO_WRITE_PROTO (adlib_write)
     adlib_kill_timers (s);
 
 #ifdef HAS_YMF262
-    status = YMF262Write (0, a, val);
+    YMF262Write (0, a, val);
 #else
-    status = OPLWrite (s->opl, a, val);
+    OPLWrite (s->opl, a, val);
 #endif
 }
 
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index ec7ea8207b..c7e365b2a6 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2401,7 +2401,7 @@ static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
 
 static void map_linear_vram(CirrusVGAState *s)
 {
-    if (!s->linear_vram) {
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) {
         s->linear_vram = true;
         memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
     }
@@ -2411,7 +2411,7 @@ static void map_linear_vram(CirrusVGAState *s)
 
 static void unmap_linear_vram(CirrusVGAState *s)
 {
-    if (s->linear_vram) {
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && s->linear_vram) {
         s->linear_vram = false;
         memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
     }
diff --git a/hw/e1000.c b/hw/e1000.c
index 6a3a941488..ce8fc8b510 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1151,8 +1151,6 @@ static int pci_e1000_init(PCIDevice *pci_dev)
 
     pci_conf = d->dev.config;
 
-    /* TODO: we have no capabilities, so why is this bit set? */
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
 
diff --git a/hw/irq.c b/hw/irq.c
index 60eabe8901..62f766eb6f 100644
--- a/hw/irq.c
+++ b/hw/irq.c
@@ -90,3 +90,17 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
     s[1] = irq2;
     return qemu_allocate_irqs(qemu_splitirq, s, 1)[0];
 }
+
+static void proxy_irq_handler(void *opaque, int n, int level)
+{
+    qemu_irq **target = opaque;
+
+    if (*target) {
+        qemu_set_irq((*target)[n], level);
+    }
+}
+
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
+{
+    return qemu_allocate_irqs(proxy_irq_handler, target, n);
+}
diff --git a/hw/irq.h b/hw/irq.h
index 389ed7a506..64da2fd601 100644
--- a/hw/irq.h
+++ b/hw/irq.h
@@ -33,4 +33,9 @@ qemu_irq qemu_irq_invert(qemu_irq irq);
 /* Returns a new IRQ which feeds into both the passed IRQs */
 qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
 
+/* Returns a new IRQ set which connects 1:1 to another IRQ set, which
+ * may be set later.
+ */
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
+
 #endif
diff --git a/hw/pc.c b/hw/pc.c
index 5bc845aaea..203627d46e 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -965,7 +965,7 @@ void pc_memory_init(MemoryRegion *system_memory,
                     const char *initrd_filename,
                     ram_addr_t below_4g_mem_size,
                     ram_addr_t above_4g_mem_size,
-                    MemoryRegion *pci_memory,
+                    MemoryRegion *rom_memory,
                     MemoryRegion **ram_memory)
 {
     char *filename;
@@ -1029,7 +1029,7 @@ void pc_memory_init(MemoryRegion *system_memory,
     isa_bios = g_malloc(sizeof(*isa_bios));
     memory_region_init_alias(isa_bios, "isa-bios", bios,
                              bios_size - isa_bios_size, isa_bios_size);
-    memory_region_add_subregion_overlap(pci_memory,
+    memory_region_add_subregion_overlap(rom_memory,
                                         0x100000 - isa_bios_size,
                                         isa_bios,
                                         1);
@@ -1037,13 +1037,13 @@ void pc_memory_init(MemoryRegion *system_memory,
 
     option_rom_mr = g_malloc(sizeof(*option_rom_mr));
     memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE);
-    memory_region_add_subregion_overlap(pci_memory,
+    memory_region_add_subregion_overlap(rom_memory,
                                         PC_ROM_MIN_VGA,
                                         option_rom_mr,
                                         1);
 
     /* map all the bios at the top of memory */
-    memory_region_add_subregion(pci_memory,
+    memory_region_add_subregion(rom_memory,
                                 (uint32_t)(-bios_size),
                                 bios);
 
diff --git a/hw/pc.h b/hw/pc.h
index dae736e7e4..8e75c71cf7 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -137,7 +137,7 @@ void pc_memory_init(MemoryRegion *system_memory,
                     const char *initrd_filename,
                     ram_addr_t below_4g_mem_size,
                     ram_addr_t above_4g_mem_size,
-                    MemoryRegion *pci_memory,
+                    MemoryRegion *rom_memory,
                     MemoryRegion **ram_memory);
 qemu_irq *pc_allocate_cpu_irq(void);
 void pc_vga_init(PCIBus *pci_bus);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 75d96d97c6..0144534e82 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -97,6 +97,7 @@ static void pc_init1(MemoryRegion *system_memory,
     ISADevice *rtc_state;
     MemoryRegion *ram_memory;
     MemoryRegion *pci_memory;
+    MemoryRegion *rom_memory;
 
     pc_cpus_init(cpu_model);
 
@@ -112,15 +113,21 @@ static void pc_init1(MemoryRegion *system_memory,
         below_4g_mem_size = ram_size;
     }
 
-    pci_memory = g_new(MemoryRegion, 1);
-    memory_region_init(pci_memory, "pci", INT64_MAX);
+    if (pci_enabled) {
+        pci_memory = g_new(MemoryRegion, 1);
+        memory_region_init(pci_memory, "pci", INT64_MAX);
+        rom_memory = pci_memory;
+    } else {
+        pci_memory = NULL;
+        rom_memory = system_memory;
+    }
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         pc_memory_init(system_memory,
                        kernel_filename, kernel_cmdline, initrd_filename,
                        below_4g_mem_size, above_4g_mem_size,
-                       pci_memory, &ram_memory);
+                       pci_enabled ? rom_memory : system_memory, &ram_memory);
     }
 
     if (!xen_enabled()) {
@@ -150,6 +157,7 @@ static void pc_init1(MemoryRegion *system_memory,
         pci_bus = NULL;
         i440fx_state = NULL;
         isa_bus_new(NULL);
+        no_hpet = 1;
     }
     isa_bus_irqs(isa_irq);
 
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 7ce95b679c..e0e54aa857 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -524,6 +524,8 @@ static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str)
         return -EINVAL;
     if (fn > 7)
         return -EINVAL;
+    if (slot > 31)
+        return -EINVAL;
     *ptr = slot << 3 | fn;
     return 0;
 }
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 0d199015d7..6b5c8ed970 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -49,6 +49,7 @@ static int vga_initfn(ISADevice *dev)
     MemoryRegion *vga_io_memory;
 
     vga_common_init(s, VGA_RAM_SIZE);
+    s->legacy_address_space = isa_address_space(dev);
     vga_io_memory = vga_init_io(s);
     memory_region_add_subregion_overlap(isa_address_space(dev),
                                         isa_mem_base + 0x000a0000,
diff --git a/hw/virtio.c b/hw/virtio.c
index d9bf266492..7011b5b398 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -16,20 +16,12 @@
 #include "trace.h"
 #include "qemu-error.h"
 #include "virtio.h"
+#include "qemu-barrier.h"
 
 /* The alignment to use between consumer and producer parts of vring.
  * x86 pagesize again. */
 #define VIRTIO_PCI_VRING_ALIGN         4096
 
-/* QEMU doesn't strictly need write barriers since everything runs in
- * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
- * KVM or if kqemu gets SMP support.
- * In any case, we must prevent the compiler from reordering the code.
- * TODO: we likely need some rmb()/mb() as well.
- */
-
-#define wmb() __asm__ __volatile__("": : :"memory")
-
 typedef struct VRingDesc
 {
     uint64_t addr;
@@ -264,7 +256,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
 {
     uint16_t old, new;
     /* Make sure buffer is written before we update index. */
-    wmb();
+    smp_wmb();
     trace_virtqueue_flush(vq, count);
     old = vring_used_idx(vq);
     new = old + count;
@@ -324,7 +316,7 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa,
     /* Check they're not leading us off end of descriptors. */
     next = vring_desc_next(desc_pa, i);
     /* Make sure compiler knows to grab that: we don't want it changing! */
-    wmb();
+    smp_wmb();
 
     if (next >= max) {
         error_report("Desc next is %u", next);
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 04e8e6e065..8677bba0d8 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -332,6 +332,49 @@ enum
     ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
 };
 
+#define TARGET_HAS_GUEST_VALIDATE_BASE
+/* We want the opportunity to check the suggested base */
+bool guest_validate_base(unsigned long guest_base)
+{
+    unsigned long real_start, test_page_addr;
+
+    /* We need to check that we can force a fault on access to the
+     * commpage at 0xffff0fxx
+     */
+    test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
+    /* Note it needs to be writeable to let us initialise it */
+    real_start = (unsigned long)
+                 mmap((void *)test_page_addr, qemu_host_page_size,
+                     PROT_READ | PROT_WRITE,
+                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+    /* If we can't map it then try another address */
+    if (real_start == -1ul) {
+        return 0;
+    }
+
+    if (real_start != test_page_addr) {
+        /* OS didn't put the page where we asked - unmap and reject */
+        munmap((void *)real_start, qemu_host_page_size);
+        return 0;
+    }
+
+    /* Leave the page mapped
+     * Populate it (mmap should have left it all 0'd)
+     */
+
+    /* Kernel helper versions */
+    __put_user(5, (uint32_t *)g2h(0xffff0ffcul));
+
+    /* Now it's populated make it RO */
+    if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) {
+        perror("Protecting guest commpage");
+        exit(-1);
+    }
+
+    return 1; /* All good */
+}
+
 #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF               \
                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT      \
                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP              \
@@ -1309,6 +1352,14 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     return sp;
 }
 
+#ifndef TARGET_HAS_GUEST_VALIDATE_BASE
+/* If the guest doesn't have a validation function just agree */
+bool guest_validate_base(unsigned long guest_base)
+{
+    return 1;
+}
+#endif
+
 static void probe_guest_base(const char *image_name,
                              abi_ulong loaddr, abi_ulong hiaddr)
 {
@@ -1345,7 +1396,9 @@ static void probe_guest_base(const char *image_name,
             if (real_start == (unsigned long)-1) {
                 goto exit_perror;
             }
-            if (real_start == host_start) {
+            guest_base = real_start - loaddr;
+            if ((real_start == host_start) &&
+                guest_validate_base(guest_base)) {
                 break;
             }
             /* That address didn't work.  Unmap and try a different one.
@@ -1368,7 +1421,6 @@ static void probe_guest_base(const char *image_name,
         qemu_log("Relocating guest address space from 0x"
                  TARGET_ABI_FMT_lx " to 0x%lx\n",
                  loaddr, real_start);
-        guest_base = real_start - loaddr;
     }
     return;
 
diff --git a/linux-user/main.c b/linux-user/main.c
index 89a51d76cd..186358bd63 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -39,6 +39,11 @@
 char *exec_path;
 
 int singlestep;
+const char *filename;
+const char *argv0;
+int gdbstub_port;
+envlist_t *envlist;
+const char *cpu_model;
 unsigned long mmap_min_addr;
 #if defined(CONFIG_USE_GUEST_BASE)
 unsigned long guest_base;
@@ -46,6 +51,8 @@ int have_guest_base;
 unsigned long reserved_va;
 #endif
 
+static void usage(void);
+
 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 
@@ -456,6 +463,83 @@ void cpu_loop(CPUX86State *env)
 
 #ifdef TARGET_ARM
 
+/*
+ * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
+ * Input:
+ * r0 = pointer to oldval
+ * r1 = pointer to newval
+ * r2 = pointer to target value
+ *
+ * Output:
+ * r0 = 0 if *ptr was changed, non-0 if no exchange happened
+ * C set if *ptr was changed, clear if no exchange happened
+ *
+ * Note segv's in kernel helpers are a bit tricky, we can set the
+ * data address sensibly but the PC address is just the entry point.
+ */
+static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
+{
+    uint64_t oldval, newval, val;
+    uint32_t addr, cpsr;
+    target_siginfo_t info;
+
+    /* Based on the 32 bit code in do_kernel_trap */
+
+    /* XXX: This only works between threads, not between processes.
+       It's probably possible to implement this with native host
+       operations. However things like ldrex/strex are much harder so
+       there's not much point trying.  */
+    start_exclusive();
+    cpsr = cpsr_read(env);
+    addr = env->regs[2];
+
+    if (get_user_u64(oldval, env->regs[0])) {
+        env->cp15.c6_data = env->regs[0];
+        goto segv;
+    };
+
+    if (get_user_u64(newval, env->regs[1])) {
+        env->cp15.c6_data = env->regs[1];
+        goto segv;
+    };
+
+    if (get_user_u64(val, addr)) {
+        env->cp15.c6_data = addr;
+        goto segv;
+    }
+
+    if (val == oldval) {
+        val = newval;
+
+        if (put_user_u64(val, addr)) {
+            env->cp15.c6_data = addr;
+            goto segv;
+        };
+
+        env->regs[0] = 0;
+        cpsr |= CPSR_C;
+    } else {
+        env->regs[0] = -1;
+        cpsr &= ~CPSR_C;
+    }
+    cpsr_write(env, cpsr, CPSR_C);
+    end_exclusive();
+    return;
+
+segv:
+    end_exclusive();
+    /* We get the PC of the entry address - which is as good as anything,
+       on a real kernel what you get depends on which mode it uses. */
+    info.si_signo = SIGSEGV;
+    info.si_errno = 0;
+    /* XXX: check env->error_code */
+    info.si_code = TARGET_SEGV_MAPERR;
+    info._sifields._sigfault._addr = env->cp15.c6_data;
+    queue_signal(env, info.si_signo, &info);
+
+    end_exclusive();
+}
+
 /* Handle a jump to the kernel code page.  */
 static int
 do_kernel_trap(CPUARMState *env)
@@ -495,6 +579,10 @@ do_kernel_trap(CPUARMState *env)
     case 0xffff0fe0: /* __kernel_get_tls */
         env->regs[0] = env->cp15.c13_tls2;
         break;
+    case 0xffff0f60: /* __kernel_cmpxchg64 */
+        arm_kernel_cmpxchg64_helper(env);
+        break;
+
     default:
         return 1;
     }
@@ -752,7 +840,6 @@ void cpu_loop(CPUARMState *env)
             goto do_segv;
         case EXCP_DATA_ABORT:
             addr = env->cp15.c6_data;
-            goto do_segv;
         do_segv:
             {
                 info.si_signo = SIGSEGV;
@@ -1669,7 +1756,7 @@ void cpu_loop(CPUPPCState *env)
 #define MIPS_SYS(name, args) args,
 
 static const uint8_t mips_syscall_args[] = {
-	MIPS_SYS(sys_syscall	, 0)	/* 4000 */
+	MIPS_SYS(sys_syscall	, 8)	/* 4000 */
 	MIPS_SYS(sys_exit	, 1)
 	MIPS_SYS(sys_fork	, 0)
 	MIPS_SYS(sys_read	, 3)
@@ -2090,11 +2177,22 @@ void cpu_loop(CPUMIPSState *env)
                 sp_reg = env->active_tc.gpr[29];
                 switch (nb_args) {
                 /* these arguments are taken from the stack */
-                /* FIXME - what to do if get_user() fails? */
-                case 8: get_user_ual(arg8, sp_reg + 28);
-                case 7: get_user_ual(arg7, sp_reg + 24);
-                case 6: get_user_ual(arg6, sp_reg + 20);
-                case 5: get_user_ual(arg5, sp_reg + 16);
+                case 8:
+                    if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
+                        goto done_syscall;
+                    }
+                case 7:
+                    if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
+                        goto done_syscall;
+                    }
+                case 6:
+                    if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
+                        goto done_syscall;
+                    }
+                case 5:
+                    if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
+                        goto done_syscall;
+                    }
                 default:
                     break;
                 }
@@ -2105,6 +2203,7 @@ void cpu_loop(CPUMIPSState *env)
                                  env->active_tc.gpr[7],
                                  arg5, arg6, arg7, arg8);
             }
+done_syscall:
             if (ret == -TARGET_QEMU_ESIGRETURN) {
                 /* Returning from a successful sigreturn syscall.
                    Avoid clobbering register state.  */
@@ -2787,57 +2886,6 @@ void cpu_loop(CPUS390XState *env)
 
 #endif /* TARGET_S390X */
 
-static void version(void)
-{
-    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
-           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
-}
-
-static void usage(void)
-{
-    version();
-    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
-           "Linux CPU emulator (compiled for %s emulation)\n"
-           "\n"
-           "Standard options:\n"
-           "-h                print this help\n"
-           "-version          display version information and exit\n"
-           "-g port           wait gdb connection to port\n"
-           "-L path           set the elf interpreter prefix (default=%s)\n"
-           "-s size           set the stack size in bytes (default=%ld)\n"
-           "-cpu model        select CPU (-cpu ? for list)\n"
-           "-drop-ld-preload  drop LD_PRELOAD for target process\n"
-           "-E var=value      sets/modifies targets environment variable(s)\n"
-           "-U var            unsets targets environment variable(s)\n"
-           "-0 argv0          forces target process argv[0] to be argv0\n"
-#if defined(CONFIG_USE_GUEST_BASE)
-           "-B address        set guest_base address to address\n"
-           "-R size           reserve size bytes for guest virtual address space\n"
-#endif
-           "\n"
-           "Debug options:\n"
-           "-d options   activate log (logfile=%s)\n"
-           "-p pagesize  set the host page size to 'pagesize'\n"
-           "-singlestep  always run in singlestep mode\n"
-           "-strace      log system calls\n"
-           "\n"
-           "Environment variables:\n"
-           "QEMU_STRACE       Print system calls and arguments similar to the\n"
-           "                  'strace' program.  Enable by setting to any value.\n"
-           "You can use -E and -U options to set/unset environment variables\n"
-           "for target process.  It is possible to provide several variables\n"
-           "by repeating the option.  For example:\n"
-           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
-           "Note that if you provide several changes to single variable\n"
-           "last change will stay in effect.\n"
-           ,
-           TARGET_ARCH,
-           interp_prefix,
-           guest_stack_size,
-           DEBUG_LOGFILE);
-    exit(1);
-}
-
 THREAD CPUState *thread_env;
 
 void task_settid(TaskState *ts)
@@ -2873,26 +2921,358 @@ void init_task_state(TaskState *ts)
     }
     ts->sigqueue_table[i].next = NULL;
 }
- 
+
+static void handle_arg_help(const char *arg)
+{
+    usage();
+}
+
+static void handle_arg_log(const char *arg)
+{
+    int mask;
+    const CPULogItem *item;
+
+    mask = cpu_str_to_log_mask(arg);
+    if (!mask) {
+        printf("Log items (comma separated):\n");
+        for (item = cpu_log_items; item->mask != 0; item++) {
+            printf("%-10s %s\n", item->name, item->help);
+        }
+        exit(1);
+    }
+    cpu_set_log(mask);
+}
+
+static void handle_arg_set_env(const char *arg)
+{
+    char *r, *p, *token;
+    r = p = strdup(arg);
+    while ((token = strsep(&p, ",")) != NULL) {
+        if (envlist_setenv(envlist, token) != 0) {
+            usage();
+        }
+    }
+    free(r);
+}
+
+static void handle_arg_unset_env(const char *arg)
+{
+    char *r, *p, *token;
+    r = p = strdup(arg);
+    while ((token = strsep(&p, ",")) != NULL) {
+        if (envlist_unsetenv(envlist, token) != 0) {
+            usage();
+        }
+    }
+    free(r);
+}
+
+static void handle_arg_argv0(const char *arg)
+{
+    argv0 = strdup(arg);
+}
+
+static void handle_arg_stack_size(const char *arg)
+{
+    char *p;
+    guest_stack_size = strtoul(arg, &p, 0);
+    if (guest_stack_size == 0) {
+        usage();
+    }
+
+    if (*p == 'M') {
+        guest_stack_size *= 1024 * 1024;
+    } else if (*p == 'k' || *p == 'K') {
+        guest_stack_size *= 1024;
+    }
+}
+
+static void handle_arg_ld_prefix(const char *arg)
+{
+    interp_prefix = strdup(arg);
+}
+
+static void handle_arg_pagesize(const char *arg)
+{
+    qemu_host_page_size = atoi(arg);
+    if (qemu_host_page_size == 0 ||
+        (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+        fprintf(stderr, "page size must be a power of two\n");
+        exit(1);
+    }
+}
+
+static void handle_arg_gdb(const char *arg)
+{
+    gdbstub_port = atoi(arg);
+}
+
+static void handle_arg_uname(const char *arg)
+{
+    qemu_uname_release = strdup(arg);
+}
+
+static void handle_arg_cpu(const char *arg)
+{
+    cpu_model = strdup(arg);
+    if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
+        /* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list_id)
+        cpu_list_id(stdout, &fprintf, "");
+#elif defined(cpu_list)
+        cpu_list(stdout, &fprintf); /* deprecated */
+#endif
+        exit(1);
+    }
+}
+
+#if defined(CONFIG_USE_GUEST_BASE)
+static void handle_arg_guest_base(const char *arg)
+{
+    guest_base = strtol(arg, NULL, 0);
+    have_guest_base = 1;
+}
+
+static void handle_arg_reserved_va(const char *arg)
+{
+    char *p;
+    int shift = 0;
+    reserved_va = strtoul(arg, &p, 0);
+    switch (*p) {
+    case 'k':
+    case 'K':
+        shift = 10;
+        break;
+    case 'M':
+        shift = 20;
+        break;
+    case 'G':
+        shift = 30;
+        break;
+    }
+    if (shift) {
+        unsigned long unshifted = reserved_va;
+        p++;
+        reserved_va <<= shift;
+        if (((reserved_va >> shift) != unshifted)
+#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
+            || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
+#endif
+            ) {
+            fprintf(stderr, "Reserved virtual address too big\n");
+            exit(1);
+        }
+    }
+    if (*p) {
+        fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
+        exit(1);
+    }
+}
+#endif
+
+static void handle_arg_singlestep(const char *arg)
+{
+    singlestep = 1;
+}
+
+static void handle_arg_strace(const char *arg)
+{
+    do_strace = 1;
+}
+
+static void handle_arg_version(const char *arg)
+{
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
+           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+}
+
+struct qemu_argument {
+    const char *argv;
+    const char *env;
+    bool has_arg;
+    void (*handle_opt)(const char *arg);
+    const char *example;
+    const char *help;
+};
+
+struct qemu_argument arg_table[] = {
+    {"h",          "",                 false, handle_arg_help,
+     "",           "print this help"},
+    {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
+     "port",       "wait gdb connection to 'port'"},
+    {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
+     "path",       "set the elf interpreter prefix to 'path'"},
+    {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
+     "size",       "set the stack size to 'size' bytes"},
+    {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
+     "model",      "select CPU (-cpu ? for list)"},
+    {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
+     "var=value",  "sets targets environment variable (see below)"},
+    {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
+     "var",        "unsets targets environment variable (see below)"},
+    {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
+     "argv0",      "forces target process argv[0] to be 'argv0'"},
+    {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
+     "uname",      "set qemu uname release string to 'uname'"},
+#if defined(CONFIG_USE_GUEST_BASE)
+    {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
+     "address",    "set guest_base address to 'address'"},
+    {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
+     "size",       "reserve 'size' bytes for guest virtual address space"},
+#endif
+    {"d",          "QEMU_LOG",         true,  handle_arg_log,
+     "options",    "activate log"},
+    {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
+     "pagesize",   "set the host page size to 'pagesize'"},
+    {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
+     "",           "run in singlestep mode"},
+    {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
+     "",           "log system calls"},
+    {"version",    "QEMU_VERSION",     false, handle_arg_version,
+     "",           "log system calls"},
+    {NULL, NULL, false, NULL, NULL, NULL}
+};
+
+static void usage(void)
+{
+    struct qemu_argument *arginfo;
+    int maxarglen;
+    int maxenvlen;
+
+    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
+           "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
+           "\n"
+           "Options and associated environment variables:\n"
+           "\n");
+
+    maxarglen = maxenvlen = 0;
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (strlen(arginfo->env) > maxenvlen) {
+            maxenvlen = strlen(arginfo->env);
+        }
+        if (strlen(arginfo->argv) > maxarglen) {
+            maxarglen = strlen(arginfo->argv);
+        }
+    }
+
+    printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
+            maxenvlen+1, "Env-variable");
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (arginfo->has_arg) {
+            printf("-%s %-*s %-*s %s\n", arginfo->argv,
+                    (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
+                    maxenvlen, arginfo->env, arginfo->help);
+        } else {
+            printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
+                    maxenvlen, arginfo->env,
+                    arginfo->help);
+        }
+    }
+
+    printf("\n"
+           "Defaults:\n"
+           "QEMU_LD_PREFIX  = %s\n"
+           "QEMU_STACK_SIZE = %ld byte\n"
+           "QEMU_LOG        = %s\n",
+           interp_prefix,
+           guest_stack_size,
+           DEBUG_LOGFILE);
+
+    printf("\n"
+           "You can use -E and -U options or the QEMU_SET_ENV and\n"
+           "QEMU_UNSET_ENV environment variables to set and unset\n"
+           "environment variables for the target process.\n"
+           "It is possible to provide several variables by separating them\n"
+           "by commas in getsubopt(3) style. Additionally it is possible to\n"
+           "provide the -E and -U options multiple times.\n"
+           "The following lines are equivalent:\n"
+           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
+           "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
+           "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
+           "Note that if you provide several changes to a single variable\n"
+           "the last change will stay in effect.\n");
+
+    exit(1);
+}
+
+static int parse_args(int argc, char **argv)
+{
+    const char *r;
+    int optind;
+    struct qemu_argument *arginfo;
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (arginfo->env == NULL) {
+            continue;
+        }
+
+        r = getenv(arginfo->env);
+        if (r != NULL) {
+            arginfo->handle_opt(r);
+        }
+    }
+
+    optind = 1;
+    for (;;) {
+        if (optind >= argc) {
+            break;
+        }
+        r = argv[optind];
+        if (r[0] != '-') {
+            break;
+        }
+        optind++;
+        r++;
+        if (!strcmp(r, "-")) {
+            break;
+        }
+
+        for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+            if (!strcmp(r, arginfo->argv)) {
+                if (optind >= argc) {
+                    usage();
+                }
+
+                arginfo->handle_opt(argv[optind]);
+
+                if (arginfo->has_arg) {
+                    optind++;
+                }
+
+                break;
+            }
+        }
+
+        /* no option matched the current argv */
+        if (arginfo->handle_opt == NULL) {
+            usage();
+        }
+    }
+
+    if (optind >= argc) {
+        usage();
+    }
+
+    filename = argv[optind];
+    exec_path = argv[optind];
+
+    return optind;
+}
+
 int main(int argc, char **argv, char **envp)
 {
-    const char *filename;
-    const char *cpu_model;
     const char *log_file = DEBUG_LOGFILE;
-    const char *log_mask = NULL;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
     struct linux_binprm bprm;
     TaskState *ts;
     CPUState *env;
     int optind;
-    const char *r;
-    int gdbstub_port = 0;
     char **target_environ, **wrk;
     char **target_argv;
     int target_argc;
-    envlist_t *envlist = NULL;
-    const char *argv0 = NULL;
     int i;
     int ret;
 
@@ -2927,156 +3307,9 @@ int main(int argc, char **argv, char **envp)
     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
 #endif
 
-    optind = 1;
-    for(;;) {
-        if (optind >= argc)
-            break;
-        r = argv[optind];
-        if (r[0] != '-')
-            break;
-        optind++;
-        r++;
-        if (!strcmp(r, "-")) {
-            break;
-        } else if (!strcmp(r, "d")) {
-            if (optind >= argc) {
-		break;
-            }
-            log_mask = argv[optind++];
-        } else if (!strcmp(r, "D")) {
-            if (optind >= argc) {
-                break;
-            }
-            log_file = argv[optind++];
-        } else if (!strcmp(r, "E")) {
-            r = argv[optind++];
-            if (envlist_setenv(envlist, r) != 0)
-                usage();
-        } else if (!strcmp(r, "ignore-environment")) {
-            envlist_free(envlist);
-            if ((envlist = envlist_create()) == NULL) {
-                (void) fprintf(stderr, "Unable to allocate envlist\n");
-                exit(1);
-            }
-        } else if (!strcmp(r, "U")) {
-            r = argv[optind++];
-            if (envlist_unsetenv(envlist, r) != 0)
-                usage();
-        } else if (!strcmp(r, "0")) {
-            r = argv[optind++];
-            argv0 = r;
-        } else if (!strcmp(r, "s")) {
-            if (optind >= argc)
-                break;
-            r = argv[optind++];
-            guest_stack_size = strtoul(r, (char **)&r, 0);
-            if (guest_stack_size == 0)
-                usage();
-            if (*r == 'M')
-                guest_stack_size *= 1024 * 1024;
-            else if (*r == 'k' || *r == 'K')
-                guest_stack_size *= 1024;
-        } else if (!strcmp(r, "L")) {
-            interp_prefix = argv[optind++];
-        } else if (!strcmp(r, "p")) {
-            if (optind >= argc)
-                break;
-            qemu_host_page_size = atoi(argv[optind++]);
-            if (qemu_host_page_size == 0 ||
-                (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
-                fprintf(stderr, "page size must be a power of two\n");
-                exit(1);
-            }
-        } else if (!strcmp(r, "g")) {
-            if (optind >= argc)
-                break;
-            gdbstub_port = atoi(argv[optind++]);
-	} else if (!strcmp(r, "r")) {
-	    qemu_uname_release = argv[optind++];
-        } else if (!strcmp(r, "cpu")) {
-            cpu_model = argv[optind++];
-            if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
-/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list_id)
-                cpu_list_id(stdout, &fprintf, "");
-#elif defined(cpu_list)
-                cpu_list(stdout, &fprintf); /* deprecated */
-#endif
-                exit(1);
-            }
-#if defined(CONFIG_USE_GUEST_BASE)
-        } else if (!strcmp(r, "B")) {
-           guest_base = strtol(argv[optind++], NULL, 0);
-           have_guest_base = 1;
-        } else if (!strcmp(r, "R")) {
-            char *p;
-            int shift = 0;
-            reserved_va = strtoul(argv[optind++], &p, 0);
-            switch (*p) {
-            case 'k':
-            case 'K':
-                shift = 10;
-                break;
-            case 'M':
-                shift = 20;
-                break;
-            case 'G':
-                shift = 30;
-                break;
-            }
-            if (shift) {
-                unsigned long unshifted = reserved_va;
-                p++;
-                reserved_va <<= shift;
-                if (((reserved_va >> shift) != unshifted)
-#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
-                    || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
-#endif
-                    ) {
-                    fprintf(stderr, "Reserved virtual address too big\n");
-                    exit(1);
-                }
-            }
-            if (*p) {
-                fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
-                exit(1);
-            }
-#endif
-        } else if (!strcmp(r, "drop-ld-preload")) {
-            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
-        } else if (!strcmp(r, "singlestep")) {
-            singlestep = 1;
-        } else if (!strcmp(r, "strace")) {
-            do_strace = 1;
-        } else if (!strcmp(r, "version")) {
-            version();
-            exit(0);
-        } else {
-            usage();
-        }
-    }
     /* init debug */
     cpu_set_log_filename(log_file);
-    if (log_mask) {
-        int mask;
-        const CPULogItem *item;
-
-        mask = cpu_str_to_log_mask(log_mask);
-        if (!mask) {
-            printf("Log items (comma separated):\n");
-            for (item = cpu_log_items; item->mask != 0; item++) {
-                printf("%-10s %s\n", item->name, item->help);
-            }
-            exit(1);
-        }
-        cpu_set_log(mask);
-    }
-
-    if (optind >= argc) {
-        usage();
-    }
-    filename = argv[optind];
-    exec_path = argv[optind];
+    optind = parse_args(argc, argv);
 
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
@@ -3180,6 +3413,13 @@ int main(int argc, char **argv, char **envp)
         }
         qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
     }
+
+    if (reserved_va || have_guest_base) {
+        if (!guest_validate_base(guest_base)) {
+            fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
+            exit(1);
+        }
+    }
 #endif /* CONFIG_USE_GUEST_BASE */
 
     /*
@@ -3568,7 +3808,11 @@ int main(int argc, char **argv, char **envp)
 #endif
 
     if (gdbstub_port) {
-        gdbserver_start (gdbstub_port);
+        if (gdbserver_start(gdbstub_port) < 0) {
+            fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
+                    gdbstub_port);
+            exit(1);
+        }
         gdb_handlesig(env, 0);
     }
     cpu_loop(env);
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 627c8b3423..55ad9d8586 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -202,6 +202,12 @@ int get_osversion(void);
 void fork_start(void);
 void fork_end(int child);
 
+/* Return true if the proposed guest_base is suitable for the guest.
+ * The guest code may leave a page mapped and populate it if the
+ * address is suitable.
+ */
+bool guest_validate_base(unsigned long guest_base);
+
 #include "qemu-log.h"
 
 /* strace.c */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6b73769c34..7735008d6a 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -70,6 +70,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #ifdef CONFIG_EPOLL
 #include <sys/epoll.h>
 #endif
+#ifdef CONFIG_ATTR
+#include <attr/xattr.h>
+#endif
 
 #define termios host_termios
 #define winsize host_winsize
@@ -796,6 +799,15 @@ abi_long do_brk(abi_ulong new_brk)
                                         MAP_ANON|MAP_PRIVATE, 0, 0));
 
     if (mapped_addr == brk_page) {
+        /* Heap contents are initialized to zero, as for anonymous
+         * mapped pages.  Technically the new pages are already
+         * initialized to zero since they *are* anonymous mapped
+         * pages, however we have to take care with the contents that
+         * come from the remaining part of the previous page: it may
+         * contains garbage data due to a previous heap usage (grown
+         * then shrunken).  */
+        memset(g2h(target_brk), 0, brk_page - target_brk);
+
         target_brk = new_brk;
         brk_page = HOST_PAGE_ALIGN(target_brk);
         DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
@@ -7632,22 +7644,67 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
         break;
 #endif
+#ifdef CONFIG_ATTR
 #ifdef TARGET_NR_setxattr
-    case TARGET_NR_setxattr:
     case TARGET_NR_lsetxattr:
     case TARGET_NR_fsetxattr:
-    case TARGET_NR_getxattr:
     case TARGET_NR_lgetxattr:
     case TARGET_NR_fgetxattr:
     case TARGET_NR_listxattr:
     case TARGET_NR_llistxattr:
     case TARGET_NR_flistxattr:
-    case TARGET_NR_removexattr:
     case TARGET_NR_lremovexattr:
     case TARGET_NR_fremovexattr:
         ret = -TARGET_EOPNOTSUPP;
         break;
+    case TARGET_NR_setxattr:
+        {
+            void *p, *n, *v;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            v = lock_user(VERIFY_READ, arg3, arg4, 1);
+            if (p && n && v) {
+                ret = get_errno(setxattr(p, n, v, arg4, arg5));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, 0);
+        }
+        break;
+    case TARGET_NR_getxattr:
+        {
+            void *p, *n, *v;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+            if (p && n && v) {
+                ret = get_errno(getxattr(p, n, v, arg4));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, arg4);
+        }
+        break;
+    case TARGET_NR_removexattr:
+        {
+            void *p, *n;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            if (p && n) {
+                ret = get_errno(removexattr(p, n));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+        }
+        break;
 #endif
+#endif /* CONFIG_ATTR */
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
 #if defined(TARGET_MIPS)
diff --git a/osdep.h b/osdep.h
index 252d050e62..432b91ea72 100644
--- a/osdep.h
+++ b/osdep.h
@@ -81,13 +81,6 @@
 
 #define qemu_printf printf
 
-#if defined (__GNUC__) && defined (__GNUC_MINOR__)
-# define QEMU_GNUC_PREREQ(maj, min) \
-         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#else
-# define QEMU_GNUC_PREREQ(maj, min) 0
-#endif
-
 int qemu_daemon(int nochdir, int noclose);
 void *qemu_memalign(size_t alignment, size_t size);
 void *qemu_vmalloc(size_t size);
diff --git a/qemu-barrier.h b/qemu-barrier.h
index b77fce23a9..735eea6cf9 100644
--- a/qemu-barrier.h
+++ b/qemu-barrier.h
@@ -1,10 +1,38 @@
 #ifndef __QEMU_BARRIER_H
 #define __QEMU_BARRIER_H 1
 
-/* FIXME: arch dependant, x86 version */
-#define smp_wmb()   asm volatile("" ::: "memory")
-
 /* Compiler barrier */
 #define barrier()   asm volatile("" ::: "memory")
 
+#if defined(__i386__) || defined(__x86_64__)
+
+/*
+ * Because of the strongly ordered x86 storage model, wmb() is a nop
+ * on x86(well, a compiler barrier only).  Well, at least as long as
+ * qemu doesn't do accesses to write-combining memory or non-temporal
+ * load/stores from C code.
+ */
+#define smp_wmb()   barrier()
+
+#elif defined(__powerpc__)
+
+/*
+ * We use an eieio() for a wmb() on powerpc.  This assumes we don't
+ * need to order cacheable and non-cacheable stores with respect to
+ * each other
+ */
+#define smp_wmb()   asm volatile("eieio" ::: "memory")
+
+#else
+
+/*
+ * For (host) platforms we don't have explicit barrier definitions
+ * for, we use the gcc __sync_synchronize() primitive to generate a
+ * full barrier.  This should be safe on all platforms, though it may
+ * be overkill.
+ */
+#define smp_wmb()   __sync_synchronize()
+
+#endif
+
 #endif
diff --git a/qemu-char.c b/qemu-char.c
index c9e5c41dc1..09d2309eb6 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1881,7 +1881,7 @@ static void udp_chr_close(CharDriverState *chr)
 {
     NetCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
     g_free(s);
@@ -2093,9 +2093,9 @@ static void tcp_chr_read(void *opaque)
         /* connection closed */
         s->connected = 0;
         if (s->listen_fd >= 0) {
-            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+            qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         }
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
         s->fd = -1;
         qemu_chr_event(chr, CHR_EVENT_CLOSED);
@@ -2156,7 +2156,7 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd)
     if (s->do_nodelay)
         socket_set_nodelay(fd);
     s->fd = fd;
-    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+    qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
     tcp_chr_connect(chr);
 
     return 0;
@@ -2202,11 +2202,11 @@ static void tcp_chr_close(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
     if (s->listen_fd >= 0) {
-        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
         closesocket(s->listen_fd);
     }
     g_free(s);
@@ -2272,7 +2272,7 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
 
     if (is_listen) {
         s->listen_fd = fd;
-        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         if (is_telnet)
             s->do_telnetopt = 1;
 
diff --git a/qemu-common.h b/qemu-common.h
index 404c421a5d..5e87bdf2f2 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -276,9 +276,6 @@ void cpu_exec_init_all(void);
 void cpu_save(QEMUFile *f, void *opaque);
 int cpu_load(QEMUFile *f, void *opaque, int version_id);
 
-/* Force QEMU to stop what it's doing and service IO */
-void qemu_service_io(void);
-
 /* Force QEMU to process pending events */
 void qemu_notify_event(void);
 
diff --git a/qemu-tool.c b/qemu-tool.c
index eb89fe0c1b..e9f7fe1e1a 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -29,10 +29,6 @@ struct QEMUBH
     void *opaque;
 };
 
-void qemu_service_io(void)
-{
-}
-
 Monitor *cur_mon;
 
 int monitor_cur_is_qmp(void)
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index 867dc1d17d..c031fcb75a 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -88,7 +88,7 @@ void kvmppc_fdt_update(void *fdt)
 
 static void kvmppc_timer_hack(void *opaque)
 {
-    qemu_service_io();
+    qemu_notify_event();
     qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate);
 }