diff options
-rw-r--r-- | backends/hostmem.c | 4 | ||||
-rwxr-xr-x | configure | 12 | ||||
-rw-r--r-- | cpu-exec.c | 1 | ||||
-rw-r--r-- | cpus.c | 31 | ||||
-rw-r--r-- | docs/bootindex.txt | 9 | ||||
-rw-r--r-- | exec.c | 4 | ||||
-rw-r--r-- | hw/core/ptimer.c | 1 | ||||
-rw-r--r-- | hw/i386/kvm/clock.c | 6 | ||||
-rw-r--r-- | hw/ppc/pnv.c | 1 | ||||
-rw-r--r-- | hw/scsi/mptsas.c | 6 | ||||
-rw-r--r-- | include/exec/memory.h | 18 | ||||
-rw-r--r-- | include/qemu/osdep.h | 3 | ||||
-rw-r--r-- | include/qemu/timer.h | 29 | ||||
-rw-r--r-- | include/sysemu/cpus.h | 3 | ||||
-rw-r--r-- | kvm-all.c | 1 | ||||
-rw-r--r-- | memory.c | 21 | ||||
-rw-r--r-- | monitor.c | 1 | ||||
-rw-r--r-- | nbd/client.c | 2 | ||||
-rw-r--r-- | qemu-options.hx | 5 | ||||
-rw-r--r-- | replay/replay.c | 1 | ||||
-rw-r--r-- | scripts/dump-guest-memory.py | 14 | ||||
-rw-r--r-- | stubs/cpu-get-icount.c | 6 | ||||
-rw-r--r-- | target/alpha/translate.c | 1 | ||||
-rw-r--r-- | target/i386/kvm.c | 12 | ||||
-rw-r--r-- | target/nios2/op_helper.c | 3 | ||||
-rw-r--r-- | tests/test-aio-multithread.c | 2 | ||||
-rw-r--r-- | tests/test-aio.c | 2 | ||||
-rw-r--r-- | translate-all.c | 1 | ||||
-rw-r--r-- | util/async.c | 2 | ||||
-rw-r--r-- | util/main-loop.c | 3 | ||||
-rw-r--r-- | util/oslib-posix.c | 108 | ||||
-rw-r--r-- | util/oslib-win32.c | 3 | ||||
-rw-r--r-- | util/path.c | 1 | ||||
-rw-r--r-- | util/qemu-timer.c | 17 | ||||
-rw-r--r-- | vl.c | 5 |
35 files changed, 274 insertions, 65 deletions
diff --git a/backends/hostmem.c b/backends/hostmem.c index 7f5de70609..162c2187d8 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -224,7 +224,7 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value, void *ptr = memory_region_get_ram_ptr(&backend->mr); uint64_t sz = memory_region_size(&backend->mr); - os_mem_prealloc(fd, ptr, sz, &local_err); + os_mem_prealloc(fd, ptr, sz, smp_cpus, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -328,7 +328,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp) */ if (backend->prealloc) { os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz, - &local_err); + smp_cpus, &local_err); if (local_err) { goto out; } @@ -1330,6 +1330,12 @@ Advanced options (experts only): --with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent --with-win-sdk=SDK-path path to Windows Platform SDK (to build VSS .tlb) --tls-priority default TLS protocol/cipher priority string + --enable-gprof QEMU profiling with gprof + --enable-profiler profiler support + --enable-xen-pv-domain-build + xen pv domain builder + --enable-debug-stack-usage + track the maximum stack usage of stacks created by qemu_alloc_stack Optional features, enabled with --enable-FEATURE and disabled with --disable-FEATURE, default is enabled if available: @@ -1397,6 +1403,12 @@ disabled with --disable-FEATURE, default is enabled if available: tcmalloc tcmalloc support jemalloc jemalloc support replication replication support + vhost-vsock virtio sockets device support + opengl opengl support + virglrenderer virgl rendering support + xfsctl xfsctl support + qom-cast-debug cast debugging support + tools build qemu-io, qemu-nbd and qemu-image tools NOTE: The object files are built at the place where configure is launched EOF diff --git a/cpu-exec.c b/cpu-exec.c index d04dd91ebd..748cb66bca 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -33,6 +33,7 @@ #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY) #include "hw/i386/apic.h" #endif +#include "sysemu/cpus.h" #include "sysemu/replay.h" /* -icount align implementation. */ @@ -800,6 +800,27 @@ static void qemu_cpu_kick_rr_cpu(void) } while (cpu != atomic_mb_read(&tcg_current_rr_cpu)); } +static void do_nothing(CPUState *cpu, run_on_cpu_data unused) +{ +} + +void qemu_timer_notify_cb(void *opaque, QEMUClockType type) +{ + if (!use_icount || type != QEMU_CLOCK_VIRTUAL) { + qemu_notify_event(); + return; + } + + if (!qemu_in_vcpu_thread() && first_cpu) { + /* qemu_cpu_kick is not enough to kick a halted CPU out of + * qemu_tcg_wait_io_event. async_run_on_cpu, instead, + * causes cpu_thread_is_idle to return false. This way, + * handle_icount_deadline can run. + */ + async_run_on_cpu(first_cpu, do_nothing, RUN_ON_CPU_NULL); + } +} + static void kick_tcg_thread(void *opaque) { timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick()); @@ -1145,12 +1166,15 @@ static int64_t tcg_get_icount_limit(void) static void handle_icount_deadline(void) { + assert(qemu_in_vcpu_thread()); if (use_icount) { int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); if (deadline == 0) { + /* Wake up other AioContexts. */ qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); } } } @@ -1263,6 +1287,11 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) /* Account partial waits to QEMU_CLOCK_VIRTUAL. */ qemu_account_warp_timer(); + /* Run the timers here. This is much more efficient than + * waking up the I/O thread and waiting for completion. + */ + handle_icount_deadline(); + if (!cpu) { cpu = first_cpu; } @@ -1304,8 +1333,6 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) atomic_mb_set(&cpu->exit_request, 0); } - handle_icount_deadline(); - qemu_tcg_wait_io_event(cpu ? cpu : QTAILQ_FIRST(&cpus)); deal_with_unplugged_cpus(); } diff --git a/docs/bootindex.txt b/docs/bootindex.txt index f84fac7200..b9a8ba122f 100644 --- a/docs/bootindex.txt +++ b/docs/bootindex.txt @@ -41,3 +41,12 @@ has three bootable devices target1, target3, target5 connected to it, the option ROM will have a boot method for each of them, but it is not possible to map from boot method back to a specific target. This is a shortcoming of the PC BIOS boot specification. + +== Mixing bootindex and boot order parameters == + +Note that it does not make sense to use the bootindex property together +with the "-boot order=..." (or "-boot once=...") parameter. The guest +firmware implementations normally either support the one or the other, +but not both parameters at the same time. Mixing them will result in +undefined behavior, and thus the guest firmware will likely not boot +from the expected devices. @@ -43,6 +43,7 @@ #include "exec/ioport.h" #include "sysemu/dma.h" #include "sysemu/numa.h" +#include "sysemu/hw_accel.h" #include "exec/address-spaces.h" #include "sysemu/xen-mapcache.h" #include "trace-root.h" @@ -1467,7 +1468,7 @@ static void *file_ram_alloc(RAMBlock *block, } if (mem_prealloc) { - os_mem_prealloc(fd, area, memory, errp); + os_mem_prealloc(fd, area, memory, smp_cpus, errp); if (errp && *errp) { goto error; } @@ -3309,6 +3310,7 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, hwaddr phys_addr; target_ulong page; + cpu_synchronize_state(cpu); while (len > 0) { int asidx; MemTxAttrs attrs; diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 59ccb00550..7221c68a98 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -13,6 +13,7 @@ #include "sysemu/replay.h" #include "sysemu/qtest.h" #include "block/aio.h" +#include "sysemu/cpus.h" #define DELTA_ADJUST 1 #define DELTA_NO_ADJUST -1 diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index ef9d560f9c..13eca374cd 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -22,6 +22,7 @@ #include "kvm_i386.h" #include "hw/sysbus.h" #include "hw/kvm/clock.h" +#include "qapi/error.h" #include <linux/kvm.h> #include <linux/kvm_para.h> @@ -208,6 +209,11 @@ static void kvmclock_realize(DeviceState *dev, Error **errp) { KVMClockState *s = KVM_CLOCK(dev); + if (!kvm_enabled()) { + error_setg(errp, "kvmclock device requires KVM"); + return; + } + kvm_update_clock(s); qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 09f0d22def..3fa722af82 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "sysemu/sysemu.h" #include "sysemu/numa.h" +#include "sysemu/cpus.h" #include "hw/hw.h" #include "target/ppc/cpu.h" #include "qemu/log.h" diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 2e091c0156..765ab53c34 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -756,7 +756,7 @@ static void mptsas_fetch_request(MPTSASState *s) /* Read the message header from the guest first. */ addr = s->host_mfa_high_addr | MPTSAS_FIFO_GET(s, request_post); - pci_dma_read(pci, addr, req, sizeof(hdr)); + pci_dma_read(pci, addr, req, sizeof(*hdr)); if (hdr->Function < ARRAY_SIZE(mpi_request_sizes) && mpi_request_sizes[hdr->Function]) { @@ -766,8 +766,8 @@ static void mptsas_fetch_request(MPTSASState *s) */ size = mpi_request_sizes[hdr->Function]; assert(size <= MPTSAS_MAX_REQUEST_SIZE); - pci_dma_read(pci, addr + sizeof(hdr), &req[sizeof(hdr)], - size - sizeof(hdr)); + pci_dma_read(pci, addr + sizeof(*hdr), &req[sizeof(*hdr)], + size - sizeof(*hdr)); } if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) { diff --git a/include/exec/memory.h b/include/exec/memory.h index 691102317c..e39256ad03 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -371,7 +371,8 @@ void memory_region_init_io(MemoryRegion *mr, * * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count - * @name: the name of the region. + * @name: Region name, becomes part of RAMBlock name used in migration stream + * must be unique within any device * @size: size of the region. * @errp: pointer to Error*, to store an error if it happens. */ @@ -390,7 +391,8 @@ void memory_region_init_ram(MemoryRegion *mr, * * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count - * @name: the name of the region. + * @name: Region name, becomes part of RAMBlock name used in migration stream + * must be unique within any device * @size: used size of the region. * @max_size: max size of the region. * @resized: callback to notify owner about used size change. @@ -412,7 +414,8 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, * * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count - * @name: the name of the region. + * @name: Region name, becomes part of RAMBlock name used in migration stream + * must be unique within any device * @size: size of the region. * @share: %true if memory must be mmaped with the MAP_SHARED flag * @path: the path in which to allocate the RAM. @@ -434,7 +437,8 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, * * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count - * @name: the name of the region. + * @name: Region name, becomes part of RAMBlock name used in migration stream + * must be unique within any device * @size: size of the region. * @ptr: memory to be mapped; must contain at least @size bytes. */ @@ -496,7 +500,8 @@ void memory_region_init_alias(MemoryRegion *mr, * * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count - * @name: the name of the region. + * @name: Region name, becomes part of RAMBlock name used in migration stream + * must be unique within any device * @size: size of the region. * @errp: pointer to Error*, to store an error if it happens. */ @@ -513,7 +518,8 @@ void memory_region_init_rom(MemoryRegion *mr, * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count * @ops: callbacks for write access handling (must not be NULL). - * @name: the name of the region. + * @name: Region name, becomes part of RAMBlock name used in migration stream + * must be unique within any device * @size: size of the region. * @errp: pointer to Error*, to store an error if it happens. */ diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index af37195fef..122ff06ff6 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -438,7 +438,8 @@ unsigned long qemu_getauxval(unsigned long type); void qemu_set_tty_echo(int fd, bool echo); -void os_mem_prealloc(int fd, char *area, size_t sz, Error **errp); +void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus, + Error **errp); int qemu_read_password(char *buf, int buf_size); diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 26e628584c..e1742f2f3d 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -4,7 +4,6 @@ #include "qemu-common.h" #include "qemu/notify.h" #include "qemu/host-utils.h" -#include "sysemu/cpus.h" #define NANOSECONDS_PER_SECOND 1000000000LL @@ -60,7 +59,7 @@ struct QEMUTimerListGroup { }; typedef void QEMUTimerCB(void *opaque); -typedef void QEMUTimerListNotifyCB(void *opaque); +typedef void QEMUTimerListNotifyCB(void *opaque, QEMUClockType type); struct QEMUTimer { int64_t expire_time; /* in nanoseconds */ @@ -534,6 +533,12 @@ static inline QEMUTimer *timer_new_tl(QEMUTimerList *timer_list, * Create a new timer and associate it with the default * timer list for the clock type @type. * + * The default timer list has one special feature: in icount mode, + * %QEMU_CLOCK_VIRTUAL timers are run in the vCPU thread. This is + * not true of other timer lists, which are typically associated + * with an AioContext---each of them runs its timer callbacks in its own + * AioContext thread. + * * Returns: a pointer to the timer */ static inline QEMUTimer *timer_new(QEMUClockType type, int scale, @@ -551,6 +556,12 @@ static inline QEMUTimer *timer_new(QEMUClockType type, int scale, * Create a new timer with nanosecond scale on the default timer list * associated with the clock. * + * The default timer list has one special feature: in icount mode, + * %QEMU_CLOCK_VIRTUAL timers are run in the vCPU thread. This is + * not true of other timer lists, which are typically associated + * with an AioContext---each of them runs its timer callbacks in its own + * AioContext thread. + * * Returns: a pointer to the newly created timer */ static inline QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb, @@ -565,6 +576,12 @@ static inline QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb, * @cb: the callback to call when the timer expires * @opaque: the opaque pointer to pass to the callback * + * The default timer list has one special feature: in icount mode, + * %QEMU_CLOCK_VIRTUAL timers are run in the vCPU thread. This is + * not true of other timer lists, which are typically associated + * with an AioContext---each of them runs its timer callbacks in its own + * AioContext thread. + * * Create a new timer with microsecond scale on the default timer list * associated with the clock. * @@ -582,6 +599,12 @@ static inline QEMUTimer *timer_new_us(QEMUClockType type, QEMUTimerCB *cb, * @cb: the callback to call when the timer expires * @opaque: the opaque pointer to pass to the callback * + * The default timer list has one special feature: in icount mode, + * %QEMU_CLOCK_VIRTUAL timers are run in the vCPU thread. This is + * not true of other timer lists, which are typically associated + * with an AioContext---each of them runs its timer callbacks in its own + * AioContext thread. + * * Create a new timer with millisecond scale on the default timer list * associated with the clock. * @@ -777,7 +800,7 @@ static inline int64_t qemu_soonest_timeout(int64_t timeout1, int64_t timeout2) * * Initialise the clock & timer infrastructure */ -void init_clocks(void); +void init_clocks(QEMUTimerListNotifyCB *notify_cb); int64_t cpu_get_ticks(void); /* Caller must hold BQL */ diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index a73b5d4bce..a8053f1715 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -1,6 +1,8 @@ #ifndef QEMU_CPUS_H #define QEMU_CPUS_H +#include "qemu/timer.h" + /* cpus.c */ bool qemu_in_vcpu_thread(void); void qemu_init_cpu_loop(void); @@ -20,6 +22,7 @@ void dump_drift_info(FILE *f, fprintf_function cpu_fprintf); /* Unblock cpu */ void qemu_cpu_kick_self(void); +void qemu_timer_notify_cb(void *opaque, QEMUClockType type); void cpu_synchronize_all_states(void); void cpu_synchronize_all_post_reset(void); @@ -29,6 +29,7 @@ #include "hw/s390x/adapter.h" #include "exec/gdbstub.h" #include "sysemu/kvm_int.h" +#include "sysemu/cpus.h" #include "qemu/bswap.h" #include "exec/memory.h" #include "exec/ram_addr.h" @@ -2494,6 +2494,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, MemoryRegionListHead submr_print_queue; const MemoryRegion *submr; unsigned int i; + hwaddr cur_start, cur_end; if (!mr) { return; @@ -2503,6 +2504,18 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, mon_printf(f, MTREE_INDENT); } + cur_start = base + mr->addr; + cur_end = cur_start + MR_SIZE(mr->size); + + /* + * Try to detect overflow of memory region. This should never + * happen normally. When it happens, we dump something to warn the + * user who is observing this. + */ + if (cur_start < base || cur_end < cur_start) { + mon_printf(f, "[DETECTED OVERFLOW!] "); + } + if (mr->alias) { MemoryRegionList *ml; bool found = false; @@ -2522,8 +2535,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): alias %s @%s " TARGET_FMT_plx "-" TARGET_FMT_plx "%s\n", - base + mr->addr, - base + mr->addr + MR_SIZE(mr->size), + cur_start, cur_end, mr->priority, memory_region_type((MemoryRegion *)mr), memory_region_name(mr), @@ -2534,8 +2546,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, } else { mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): %s%s\n", - base + mr->addr, - base + mr->addr + MR_SIZE(mr->size), + cur_start, cur_end, mr->priority, memory_region_type((MemoryRegion *)mr), memory_region_name(mr), @@ -2562,7 +2573,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, } QTAILQ_FOREACH(ml, &submr_print_queue, queue) { - mtree_print_mr(mon_printf, f, ml->mr, level + 1, base + mr->addr, + mtree_print_mr(mon_printf, f, ml->mr, level + 1, cur_start, alias_print_queue); } @@ -77,6 +77,7 @@ #include "qapi-event.h" #include "qmp-introspect.h" #include "sysemu/qtest.h" +#include "sysemu/cpus.h" #include "qemu/cutils.h" #include "qapi/qmp/dispatch.h" diff --git a/nbd/client.c b/nbd/client.c index 5c9dee37fa..3dc2564cd0 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -94,7 +94,7 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size) char small[1024]; char *buffer; - buffer = sizeof(small) < size ? small : g_malloc(MIN(65536, size)); + buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); while (size > 0) { ssize_t count = read_sync(ioc, buffer, MIN(65536, size)); diff --git a/qemu-options.hx b/qemu-options.hx index 8dd8ee34a6..99af8edf5f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -252,7 +252,10 @@ drive letters depend on the target architecture. The x86 PC uses: a, b (floppy 1 and 2), c (first hard disk), d (first CD-ROM), n-p (Etherboot from network adapter 1-4), hard disk boot is the default. To apply a particular boot order only on the first startup, specify it via -@option{once}. +@option{once}. Note that the @option{order} or @option{once} parameter +should not be used together with the @option{bootindex} property of +devices, since the firmware implementations normally do not support both +at the same time. Interactive boot menus/prompts can be enabled via @option{menu=on} as far as firmware/BIOS supports them. The default is non-interactive boot. diff --git a/replay/replay.c b/replay/replay.c index 1835b9902e..78e2a7e570 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -16,6 +16,7 @@ #include "replay-internal.h" #include "qemu/timer.h" #include "qemu/main-loop.h" +#include "sysemu/cpus.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py index 9956fc036c..f7c6635f15 100644 --- a/scripts/dump-guest-memory.py +++ b/scripts/dump-guest-memory.py @@ -314,8 +314,18 @@ def get_arch_phdr(endianness, elfclass): def int128_get64(val): """Returns low 64bit part of Int128 struct.""" - assert val["hi"] == 0 - return val["lo"] + try: + assert val["hi"] == 0 + return val["lo"] + except gdb.error: + u64t = gdb.lookup_type('uint64_t').array(2) + u64 = val.cast(u64t) + if sys.byteorder == 'little': + assert u64[1] == 0 + return u64[0] + else: + assert u64[0] == 0 + return u64[1] def qlist_foreach(head, field_str): diff --git a/stubs/cpu-get-icount.c b/stubs/cpu-get-icount.c index 2e8b63b225..0b7239d721 100644 --- a/stubs/cpu-get-icount.c +++ b/stubs/cpu-get-icount.c @@ -2,6 +2,7 @@ #include "qemu-common.h" #include "qemu/timer.h" #include "sysemu/cpus.h" +#include "qemu/main-loop.h" int use_icount; @@ -9,3 +10,8 @@ int64_t cpu_get_icount(void) { abort(); } + +void qemu_timer_notify_cb(void *opaque, QEMUClockType type) +{ + qemu_notify_event(); +} diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 055286a7b8..df5d695344 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "sysemu/cpus.h" #include "disas/disas.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 472399fb2c..55865dbee0 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1824,6 +1824,12 @@ static int kvm_put_msrs(X86CPU *cpu, int level) return ret; } + if (ret < cpu->kvm_msr_buf->nmsrs) { + struct kvm_msr_entry *e = &cpu->kvm_msr_buf->entries[ret]; + error_report("error: failed to set MSR 0x%" PRIx32 " to 0x%" PRIx64, + (uint32_t)e->index, (uint64_t)e->data); + } + assert(ret == cpu->kvm_msr_buf->nmsrs); return 0; } @@ -2189,6 +2195,12 @@ static int kvm_get_msrs(X86CPU *cpu) return ret; } + if (ret < cpu->kvm_msr_buf->nmsrs) { + struct kvm_msr_entry *e = &cpu->kvm_msr_buf->entries[ret]; + error_report("error: failed to get MSR 0x%" PRIx32, + (uint32_t)e->index); + } + assert(ret == cpu->kvm_msr_buf->nmsrs); /* * MTRR masks: Each mask consists of 5 parts diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c index 538853cda7..efb1c489c9 100644 --- a/target/nios2/op_helper.c +++ b/target/nios2/op_helper.c @@ -21,6 +21,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" +#include "qemu/main-loop.h" #if !defined(CONFIG_USER_ONLY) void helper_mmu_read_debug(CPUNios2State *env, uint32_t rn) @@ -35,7 +36,9 @@ void helper_mmu_write(CPUNios2State *env, uint32_t rn, uint32_t v) void helper_check_interrupts(CPUNios2State *env) { + qemu_mutex_lock_iothread(); nios2_check_interrupts(env); + qemu_mutex_unlock_iothread(); } #endif /* !CONFIG_USER_ONLY */ diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c index 8b0b40ec78..549d784915 100644 --- a/tests/test-aio-multithread.c +++ b/tests/test-aio-multithread.c @@ -438,7 +438,7 @@ static void test_multi_mutex_10(void) int main(int argc, char **argv) { - init_clocks(); + init_clocks(NULL); g_test_init(&argc, &argv, NULL); g_test_add_func("/aio/multi/lifecycle", test_lifecycle); diff --git a/tests/test-aio.c b/tests/test-aio.c index 2754f154ce..54e20d6ab1 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -835,7 +835,7 @@ int main(int argc, char **argv) Error *local_error = NULL; GSource *src; - init_clocks(); + init_clocks(NULL); ctx = aio_context_new(&local_error); if (!ctx) { diff --git a/translate-all.c b/translate-all.c index 34480aebba..b3ee876526 100644 --- a/translate-all.c +++ b/translate-all.c @@ -57,6 +57,7 @@ #include "qemu/timer.h" #include "qemu/main-loop.h" #include "exec/log.h" +#include "sysemu/cpus.h" /* #define DEBUG_TB_INVALIDATE */ /* #define DEBUG_TB_FLUSH */ diff --git a/util/async.c b/util/async.c index 7d469eb857..663e297e1f 100644 --- a/util/async.c +++ b/util/async.c @@ -351,7 +351,7 @@ void aio_notify_accept(AioContext *ctx) } } -static void aio_timerlist_notify(void *opaque) +static void aio_timerlist_notify(void *opaque, QEMUClockType type) { aio_notify(opaque); } diff --git a/util/main-loop.c b/util/main-loop.c index ca7bb072f9..4534c89308 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -28,6 +28,7 @@ #include "qemu/timer.h" #include "qemu/sockets.h" // struct in_addr needed for libslirp.h #include "sysemu/qtest.h" +#include "sysemu/cpus.h" #include "slirp/libslirp.h" #include "qemu/main-loop.h" #include "block/aio.h" @@ -143,7 +144,7 @@ int qemu_init_main_loop(Error **errp) GSource *src; Error *local_error = NULL; - init_clocks(); + init_clocks(qemu_timer_notify_cb); ret = qemu_signal_init(); if (ret) { diff --git a/util/oslib-posix.c b/util/oslib-posix.c index cd686aae3d..956f66ab4a 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -55,6 +55,21 @@ #include "qemu/error-report.h" #endif +#define MAX_MEM_PREALLOC_THREAD_COUNT (MIN(sysconf(_SC_NPROCESSORS_ONLN), 16)) + +struct MemsetThread { + char *addr; + uint64_t numpages; + uint64_t hpagesize; + QemuThread pgthread; + sigjmp_buf env; +}; +typedef struct MemsetThread MemsetThread; + +static MemsetThread *memset_thread; +static int memset_num_threads; +static bool memset_thread_failed; + int qemu_get_thread_id(void) { #if defined(__linux__) @@ -316,18 +331,83 @@ char *qemu_get_exec_dir(void) return g_strdup(exec_dir); } -static sigjmp_buf sigjump; - static void sigbus_handler(int signal) { - siglongjmp(sigjump, 1); + int i; + if (memset_thread) { + for (i = 0; i < memset_num_threads; i++) { + if (qemu_thread_is_self(&memset_thread[i].pgthread)) { + siglongjmp(memset_thread[i].env, 1); + } + } + } +} + +static void *do_touch_pages(void *arg) +{ + MemsetThread *memset_args = (MemsetThread *)arg; + char *addr = memset_args->addr; + uint64_t numpages = memset_args->numpages; + uint64_t hpagesize = memset_args->hpagesize; + sigset_t set, oldset; + int i = 0; + + /* unblock SIGBUS */ + sigemptyset(&set); + sigaddset(&set, SIGBUS); + pthread_sigmask(SIG_UNBLOCK, &set, &oldset); + + if (sigsetjmp(memset_args->env, 1)) { + memset_thread_failed = true; + } else { + for (i = 0; i < numpages; i++) { + memset(addr, 0, 1); + addr += hpagesize; + } + } + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + return NULL; +} + +static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, + int smp_cpus) +{ + uint64_t numpages_per_thread, size_per_thread; + char *addr = area; + int i = 0; + + memset_thread_failed = false; + memset_num_threads = MIN(smp_cpus, MAX_MEM_PREALLOC_THREAD_COUNT); + memset_thread = g_new0(MemsetThread, memset_num_threads); + numpages_per_thread = (numpages / memset_num_threads); + size_per_thread = (hpagesize * numpages_per_thread); + for (i = 0; i < memset_num_threads; i++) { + memset_thread[i].addr = addr; + memset_thread[i].numpages = (i == (memset_num_threads - 1)) ? + numpages : numpages_per_thread; + memset_thread[i].hpagesize = hpagesize; + qemu_thread_create(&memset_thread[i].pgthread, "touch_pages", + do_touch_pages, &memset_thread[i], + QEMU_THREAD_JOINABLE); + addr += size_per_thread; + numpages -= numpages_per_thread; + } + for (i = 0; i < memset_num_threads; i++) { + qemu_thread_join(&memset_thread[i].pgthread); + } + g_free(memset_thread); + memset_thread = NULL; + + return memset_thread_failed; } -void os_mem_prealloc(int fd, char *area, size_t memory, Error **errp) +void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, + Error **errp) { int ret; struct sigaction act, oldact; - sigset_t set, oldset; + size_t hpagesize = qemu_fd_getpagesize(fd); + size_t numpages = DIV_ROUND_UP(memory, hpagesize); memset(&act, 0, sizeof(act)); act.sa_handler = &sigbus_handler; @@ -340,23 +420,10 @@ void os_mem_prealloc(int fd, char *area, size_t memory, Error **errp) return; } - /* unblock SIGBUS */ - sigemptyset(&set); - sigaddset(&set, SIGBUS); - pthread_sigmask(SIG_UNBLOCK, &set, &oldset); - - if (sigsetjmp(sigjump, 1)) { + /* touch pages simultaneously */ + if (touch_all_pages(area, hpagesize, numpages, smp_cpus)) { error_setg(errp, "os_mem_prealloc: Insufficient free host memory " "pages available to allocate guest RAM\n"); - } else { - int i; - size_t hpagesize = qemu_fd_getpagesize(fd); - size_t numpages = DIV_ROUND_UP(memory, hpagesize); - - /* MAP_POPULATE silently ignores failures */ - for (i = 0; i < numpages; i++) { - memset(area + (hpagesize * i), 0, 1); - } } ret = sigaction(SIGBUS, &oldact, NULL); @@ -365,7 +432,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory, Error **errp) perror("os_mem_prealloc: failed to reinstall signal handler"); exit(1); } - pthread_sigmask(SIG_SETMASK, &oldset, NULL); } diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 0b1890fd33..80e4668935 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -541,7 +541,8 @@ int getpagesize(void) return system_info.dwPageSize; } -void os_mem_prealloc(int fd, char *area, size_t memory, Error **errp) +void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, + Error **errp) { int i; size_t pagesize = getpagesize(); diff --git a/util/path.c b/util/path.c index 5479f76c6d..7f9fc272fb 100644 --- a/util/path.c +++ b/util/path.c @@ -6,7 +6,6 @@ #include "qemu/osdep.h" #include <sys/param.h> #include <dirent.h> -#include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/path.h" diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 6cf70b96f6..82d56507a2 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -27,6 +27,7 @@ #include "qemu/timer.h" #include "sysemu/replay.h" #include "sysemu/sysemu.h" +#include "sysemu/cpus.h" #ifdef CONFIG_POSIX #include <pthread.h> @@ -121,7 +122,7 @@ void timerlist_free(QEMUTimerList *timer_list) g_free(timer_list); } -static void qemu_clock_init(QEMUClockType type) +static void qemu_clock_init(QEMUClockType type, QEMUTimerListNotifyCB *notify_cb) { QEMUClock *clock = qemu_clock_ptr(type); @@ -133,7 +134,7 @@ static void qemu_clock_init(QEMUClockType type) clock->last = INT64_MIN; QLIST_INIT(&clock->timerlists); notifier_list_init(&clock->reset_notifiers); - main_loop_tlg.tl[type] = timerlist_new(type, NULL, NULL); + main_loop_tlg.tl[type] = timerlist_new(type, notify_cb, NULL); } bool qemu_clock_use_for_deadline(QEMUClockType type) @@ -199,7 +200,7 @@ bool timerlist_expired(QEMUTimerList *timer_list) expire_time = timer_list->active_timers->expire_time; qemu_mutex_unlock(&timer_list->active_timers_lock); - return expire_time < qemu_clock_get_ns(timer_list->clock->type); + return expire_time <= qemu_clock_get_ns(timer_list->clock->type); } bool qemu_clock_expired(QEMUClockType type) @@ -277,7 +278,7 @@ QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type) void timerlist_notify(QEMUTimerList *timer_list) { if (timer_list->notify_cb) { - timer_list->notify_cb(timer_list->notify_opaque); + timer_list->notify_cb(timer_list->notify_opaque, timer_list->clock->type); } else { qemu_notify_event(); } @@ -634,11 +635,11 @@ void qemu_clock_unregister_reset_notifier(QEMUClockType type, notifier_remove(notifier); } -void init_clocks(void) +void init_clocks(QEMUTimerListNotifyCB *notify_cb) { QEMUClockType type; for (type = 0; type < QEMU_CLOCK_MAX; type++) { - qemu_clock_init(type); + qemu_clock_init(type, notify_cb); } #ifdef CONFIG_PRCTL_PR_SET_TIMERSLACK @@ -657,7 +658,9 @@ bool qemu_clock_run_all_timers(void) QEMUClockType type; for (type = 0; type < QEMU_CLOCK_MAX; type++) { - progress |= qemu_clock_run_timers(type); + if (qemu_clock_use_for_deadline(type)) { + progress |= qemu_clock_run_timers(type); + } } return progress; @@ -1888,17 +1888,14 @@ static bool main_loop_should_exit(void) static void main_loop(void) { - bool nonblocking; - int last_io = 0; #ifdef CONFIG_PROFILER int64_t ti; #endif do { - nonblocking = tcg_enabled() && last_io > 0; #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif - last_io = main_loop_wait(nonblocking); + main_loop_wait(false); #ifdef CONFIG_PROFILER dev_time += profile_getclock() - ti; #endif |