diff options
| -rw-r--r-- | MAINTAINERS | 5 | ||||
| -rw-r--r-- | Makefile | 36 | ||||
| -rw-r--r-- | arch_init.c | 5 | ||||
| -rw-r--r-- | compiler.h | 17 | ||||
| -rwxr-xr-x | configure | 22 | ||||
| -rw-r--r-- | host-utils.h | 2 | ||||
| -rw-r--r-- | hw/adlib.c | 5 | ||||
| -rw-r--r-- | hw/cirrus_vga.c | 4 | ||||
| -rw-r--r-- | hw/e1000.c | 2 | ||||
| -rw-r--r-- | hw/irq.c | 14 | ||||
| -rw-r--r-- | hw/irq.h | 5 | ||||
| -rw-r--r-- | hw/pc.c | 8 | ||||
| -rw-r--r-- | hw/pc.h | 2 | ||||
| -rw-r--r-- | hw/pc_piix.c | 14 | ||||
| -rw-r--r-- | hw/qdev-properties.c | 2 | ||||
| -rw-r--r-- | hw/vga-isa.c | 1 | ||||
| -rw-r--r-- | hw/virtio.c | 14 | ||||
| -rw-r--r-- | linux-user/elfload.c | 56 | ||||
| -rw-r--r-- | linux-user/main.c | 674 | ||||
| -rw-r--r-- | linux-user/qemu.h | 6 | ||||
| -rw-r--r-- | linux-user/syscall.c | 63 | ||||
| -rw-r--r-- | osdep.h | 7 | ||||
| -rw-r--r-- | qemu-barrier.h | 34 | ||||
| -rw-r--r-- | qemu-char.c | 14 | ||||
| -rw-r--r-- | qemu-common.h | 3 | ||||
| -rw-r--r-- | qemu-tool.c | 4 | ||||
| -rw-r--r-- | target-ppc/kvm_ppc.c | 2 |
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 = ®s1; 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); } |