diff --git a/Makefile b/Makefile index 50b4b3afb9..1fad5b78e5 100644 --- a/Makefile +++ b/Makefile @@ -669,3 +669,40 @@ endif -include $(wildcard *.d tests/*.d) include $(SRC_PATH)/tests/docker/Makefile.include + +.PHONY: help +help: + @echo 'Generic targets:' + @echo ' all - Build all' + @echo ' dir/file.o - Build specified target only' + @echo ' install - Install QEMU, documentation and tools' + @echo ' ctags/TAGS - Generate tags file for editors' + @echo ' cscope - Generate cscope index' + @echo '' + @$(if $(TARGET_DIRS), \ + echo 'Architecture specific targets:'; \ + $(foreach t, $(TARGET_DIRS), \ + printf " %-30s - Build for %s\\n" $(patsubst %,subdir-%,$(t)) $(t);) \ + echo '') + @echo 'Cleaning targets:' + @echo ' clean - Remove most generated files but keep the config' + @echo ' distclean - Remove all generated files' + @echo ' dist - Build a distributable tarball' + @echo '' + @echo 'Test targets:' + @echo ' check - Run all tests (check-help for details)' + @echo ' docker - Help about targets running tests inside Docker containers' + @echo '' + @echo 'Documentation targets:' + @echo ' dvi html info pdf' + @echo ' - Build documentation in specified format' + @echo '' +ifdef CONFIG_WIN32 + @echo 'Windows targets:' + @echo ' installer - Build NSIS-based installer for qemu-ga' +ifdef QEMU_GA_MSI_ENABLED + @echo ' msi - Build MSI-based installer for qemu-ga' +endif + @echo '' +endif + @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' diff --git a/backends/msmouse.c b/backends/msmouse.c index aeb905562d..aceb6dc475 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -159,6 +159,9 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id, CharDriverState *chr; chr = qemu_chr_alloc(common, errp); + if (!chr) { + return NULL; + } chr->chr_write = msmouse_chr_write; chr->chr_close = msmouse_chr_close; chr->chr_accept_input = msmouse_chr_accept_input; diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 42a6f4885a..984534b2d1 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -52,8 +52,8 @@ typedef struct { unsigned int pit_count; unsigned int samples; unsigned int play_pos; - int data_on; - int dummy_refresh_clock; + uint8_t data_on; + uint8_t dummy_refresh_clock; } PCSpkState; static const char *s_spk = "pcspk"; @@ -187,6 +187,18 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp) pcspk_state = s; } +static const VMStateDescription vmstate_spk = { + .name = "pcspk", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(data_on, PCSpkState), + VMSTATE_UINT8(dummy_refresh_clock, PCSpkState), + VMSTATE_END_OF_LIST() + } +}; + static Property pcspk_properties[] = { DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1), DEFINE_PROP_END_OF_LIST(), @@ -198,6 +210,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data) dc->realize = pcspk_realizefn; set_bit(DEVICE_CATEGORY_SOUND, dc->categories); + dc->vmsd = &vmstate_spk; dc->props = pcspk_properties; /* Reason: realize sets global pcspk_state */ dc->cannot_instantiate_with_device_add_yet = true; diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index 3bf1ddd976..a1cd9b5a29 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -768,6 +768,7 @@ static void kvmvapic_vm_state_change(void *opaque, int running, } qemu_del_vm_change_state_handler(s->vmsentry); + s->vmsentry = NULL; } static int vapic_post_load(void *opaque, int version_id) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index e31f70f428..2d6d7920ff 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -161,13 +161,15 @@ int cpu_get_pic_interrupt(CPUX86State *env) X86CPU *cpu = x86_env_get_cpu(env); int intno; - intno = apic_get_interrupt(cpu->apic_state); - if (intno >= 0) { - return intno; - } - /* read the irq from the PIC */ - if (!apic_accept_pic_intr(cpu->apic_state)) { - return -1; + if (!kvm_irqchip_in_kernel()) { + intno = apic_get_interrupt(cpu->apic_state); + if (intno >= 0) { + return intno; + } + /* read the irq from the PIC */ + if (!apic_accept_pic_intr(cpu->apic_state)) { + return -1; + } } intno = pic_read_irq(isa_pic); @@ -180,7 +182,7 @@ static void pic_irq_request(void *opaque, int irq, int level) X86CPU *cpu = X86_CPU(cs); DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq); - if (cpu->apic_state) { + if (cpu->apic_state && !kvm_irqchip_in_kernel()) { CPU_FOREACH(cs) { cpu = X86_CPU(cs); if (apic_accept_pic_intr(cpu->apic_state)) { diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 45887d99c0..7bd1d279c4 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -39,6 +39,10 @@ static APICCommonState *local_apics[MAX_APICS + 1]; +#define TYPE_APIC "apic" +#define APIC(obj) \ + OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC) + static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode); static void apic_update_irq(APICCommonState *s); static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, @@ -163,7 +167,7 @@ static void apic_local_deliver(APICCommonState *s, int vector) void apic_deliver_pic_intr(DeviceState *dev, int level) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); if (level) { apic_local_deliver(s, APIC_LVT_LINT0); @@ -373,7 +377,7 @@ static void apic_update_irq(APICCommonState *s) void apic_poll_irq(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); apic_sync_vapic(s, SYNC_FROM_VAPIC); apic_update_irq(s); @@ -479,7 +483,7 @@ static void apic_startup(APICCommonState *s, int vector_num) void apic_sipi(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); @@ -493,7 +497,7 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); uint32_t deliver_bitmask[MAX_APIC_WORDS]; int dest_shorthand = (s->icr[0] >> 18) & 3; APICCommonState *apic_iter; @@ -550,7 +554,7 @@ static bool apic_check_pic(APICCommonState *s) int apic_get_interrupt(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); int intno; /* if the APIC is installed or enabled, we let the 8259 handle the @@ -584,7 +588,7 @@ int apic_get_interrupt(DeviceState *dev) int apic_accept_pic_intr(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); uint32_t lvt0; if (!s) @@ -663,7 +667,7 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr) if (!dev) { return 0; } - s = APIC_COMMON(dev); + s = APIC(dev); index = (addr >> 4) & 0xff; switch(index) { @@ -766,7 +770,7 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) if (!dev) { return; } - s = APIC_COMMON(dev); + s = APIC(dev); trace_apic_mem_writel(addr, val); @@ -870,7 +874,7 @@ static const MemoryRegionOps apic_io_ops = { static void apic_realize(DeviceState *dev, Error **errp) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); if (s->id >= MAX_APICS) { error_setg(errp, "%s initialization failed. APIC ID %d is invalid", @@ -889,7 +893,7 @@ static void apic_realize(DeviceState *dev, Error **errp) static void apic_unrealize(DeviceState *dev, Error **errp) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); timer_del(s->timer); timer_free(s->timer); @@ -912,7 +916,7 @@ static void apic_class_init(ObjectClass *klass, void *data) } static const TypeInfo apic_info = { - .name = "apic", + .name = TYPE_APIC, .instance_size = sizeof(APICCommonState), .parent = TYPE_APIC_COMMON, .class_init = apic_class_init, diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 8a3dee17fc..ad87e78fe2 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -304,7 +304,7 @@ static int mptsas_process_scsi_io_request(MPTSASState *s, goto bad; } - req = g_new(MPTSASRequest, 1); + req = g_new0(MPTSASRequest, 1); QTAILQ_INSERT_TAIL(&s->pending, req, next); req->scsi_io = *scsi_io; req->dev = s; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 77cba31e30..88beaf4bb8 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -396,7 +396,7 @@ static void scsi_read_data(SCSIRequest *req) return; } - if (s->tray_open) { + if (!blk_is_available(req->dev->conf.blk)) { scsi_read_complete(r, -ENOMEDIUM); return; } @@ -519,7 +519,7 @@ static void scsi_write_data(SCSIRequest *req) scsi_write_complete_noio(r, 0); return; } - if (s->tray_open) { + if (!blk_is_available(req->dev->conf.blk)) { scsi_write_complete_noio(r, -ENOMEDIUM); return; } @@ -792,10 +792,7 @@ static inline bool media_is_dvd(SCSIDiskState *s) if (s->qdev.type != TYPE_ROM) { return false; } - if (!blk_is_inserted(s->qdev.conf.blk)) { - return false; - } - if (s->tray_open) { + if (!blk_is_available(s->qdev.conf.blk)) { return false; } blk_get_geometry(s->qdev.conf.blk, &nb_sectors); @@ -808,10 +805,7 @@ static inline bool media_is_cd(SCSIDiskState *s) if (s->qdev.type != TYPE_ROM) { return false; } - if (!blk_is_inserted(s->qdev.conf.blk)) { - return false; - } - if (s->tray_open) { + if (!blk_is_available(s->qdev.conf.blk)) { return false; } blk_get_geometry(s->qdev.conf.blk, &nb_sectors); @@ -875,7 +869,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r, } if (format != 0xff) { - if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) { + if (!blk_is_available(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); return -1; } @@ -1857,7 +1851,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; default: - if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) { + if (!blk_is_available(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); return 0; } @@ -1886,7 +1880,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) memset(outbuf, 0, r->buflen); switch (req->cmd.buf[0]) { case TEST_UNIT_READY: - assert(!s->tray_open && blk_is_inserted(s->qdev.conf.blk)); + assert(blk_is_available(s->qdev.conf.blk)); break; case INQUIRY: buflen = scsi_disk_emulate_inquiry(req, outbuf); @@ -2126,7 +2120,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) command = buf[0]; - if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) { + if (!blk_is_available(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); return 0; } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index ce57ef6248..e596b64741 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -236,6 +236,13 @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) g_free(n); } +static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d) +{ + if (s->dataplane_started && d && blk_is_available(d->conf.blk)) { + assert(blk_get_aio_context(d->conf.blk) == s->ctx); + } +} + /* Return 0 if the request is ready to be completed and return to guest; * -EINPROGRESS if the request is submitted and will be completed later, in the * case of async cancellation. */ @@ -247,9 +254,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) int target; int ret = 0; - if (s->dataplane_started && d) { - assert(blk_get_aio_context(d->conf.blk) == s->ctx); - } + virtio_scsi_ctx_check(s, d); /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ req->resp.tmf.response = VIRTIO_SCSI_S_OK; @@ -539,9 +544,7 @@ static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req virtio_scsi_complete_cmd_req(req); return false; } - if (s->dataplane_started) { - assert(blk_get_aio_context(d->conf.blk) == s->ctx); - } + virtio_scsi_ctx_check(s, d); req->sreq = scsi_req_new(d, req->req.cmd.tag, virtio_scsi_get_lun(req->req.cmd.lun), req->req.cmd.cdb, req); diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index babac5a68a..a5ce7dea8e 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -247,8 +247,11 @@ static hwaddr pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr) { uint32_t ready_ptr = RS_GET_FIELD(mgr, reqProdIdx); + uint32_t ring_size = PVSCSI_MAX_NUM_PAGES_REQ_RING + * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - if (ready_ptr != mgr->consumed_ptr) { + if (ready_ptr != mgr->consumed_ptr + && ready_ptr - mgr->consumed_ptr < ring_size) { uint32_t next_ready_ptr = mgr->consumed_ptr++ & mgr->txr_len_mask; uint32_t next_ready_page = diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f807baf389..29455e4e47 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2718,7 +2718,6 @@ static int core_dump_filename(const TaskState *ts, char *buf, size_t bufsize) { char timestamp[64]; - char *filename = NULL; char *base_filename = NULL; struct timeval tv; struct tm tm; @@ -2731,14 +2730,12 @@ static int core_dump_filename(const TaskState *ts, char *buf, return (-1); } - filename = strdup(ts->bprm->filename); - base_filename = strdup(basename(filename)); + base_filename = g_path_get_basename(ts->bprm->filename); (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S", localtime_r(&tv.tv_sec, &tm)); (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core", base_filename, timestamp, (int)getpid()); - free(base_filename); - free(filename); + g_free(base_filename); return (0); } diff --git a/memory.c b/memory.c index 0eb6895fe6..1a1baf574c 100644 --- a/memory.c +++ b/memory.c @@ -944,11 +944,6 @@ static void memory_region_destructor_ram(MemoryRegion *mr) qemu_ram_free(mr->ram_block); } -static void memory_region_destructor_rom_device(MemoryRegion *mr) -{ - qemu_ram_free(mr->ram_block); -} - static bool memory_region_need_escape(char c) { return c == '/' || c == '[' || c == '\\' || c == ']'; @@ -1405,7 +1400,7 @@ void memory_region_init_rom_device(MemoryRegion *mr, mr->opaque = opaque; mr->terminates = true; mr->rom_device = true; - mr->destructor = memory_region_destructor_rom_device; + mr->destructor = memory_region_destructor_ram; mr->ram_block = qemu_ram_alloc(size, mr, errp); } diff --git a/net/socket.c b/net/socket.c index 3f98eefb34..982c8debe4 100644 --- a/net/socket.c +++ b/net/socket.c @@ -489,90 +489,105 @@ static int net_socket_listen_init(NetClientState *peer, { NetClientState *nc; NetSocketState *s; - struct sockaddr_in saddr; - int fd, ret; + SocketAddress *saddr; + int ret; + Error *local_error = NULL; - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); + saddr = socket_parse(host_str, &local_error); + if (saddr == NULL) { + error_report_err(local_error); return -1; } - qemu_set_nonblock(fd); - socket_set_fast_reuse(fd); - - ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + ret = socket_listen(saddr, &local_error); if (ret < 0) { - perror("bind"); - closesocket(fd); - return -1; - } - ret = listen(fd, 0); - if (ret < 0) { - perror("listen"); - closesocket(fd); + qapi_free_SocketAddress(saddr); + error_report_err(local_error); return -1; } nc = qemu_new_net_client(&net_socket_info, peer, model, name); s = DO_UPCAST(NetSocketState, nc, nc); s->fd = -1; - s->listen_fd = fd; + s->listen_fd = ret; s->nc.link_down = true; qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); + qapi_free_SocketAddress(saddr); return 0; } +typedef struct { + NetClientState *peer; + SocketAddress *saddr; + char *model; + char *name; +} socket_connect_data; + +static void socket_connect_data_free(socket_connect_data *c) +{ + qapi_free_SocketAddress(c->saddr); + g_free(c->model); + g_free(c->name); + g_free(c); +} + +static void net_socket_connected(int fd, Error *err, void *opaque) +{ + socket_connect_data *c = opaque; + NetSocketState *s; + char *addr_str = NULL; + Error *local_error = NULL; + + addr_str = socket_address_to_string(c->saddr, &local_error); + if (addr_str == NULL) { + error_report_err(local_error); + closesocket(fd); + goto end; + } + + s = net_socket_fd_init(c->peer, c->model, c->name, fd, true); + if (!s) { + closesocket(fd); + goto end; + } + + snprintf(s->nc.info_str, sizeof(s->nc.info_str), + "socket: connect to %s", addr_str); + +end: + g_free(addr_str); + socket_connect_data_free(c); +} + static int net_socket_connect_init(NetClientState *peer, const char *model, const char *name, const char *host_str) { - NetSocketState *s; - int fd, connected, ret; - struct sockaddr_in saddr; + socket_connect_data *c = g_new0(socket_connect_data, 1); + int fd = -1; + Error *local_error = NULL; - if (parse_host_port(&saddr, host_str) < 0) - return -1; + c->peer = peer; + c->model = g_strdup(model); + c->name = g_strdup(name); + c->saddr = socket_parse(host_str, &local_error); + if (c->saddr == NULL) { + goto err; + } - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); + fd = socket_connect(c->saddr, &local_error, net_socket_connected, c); if (fd < 0) { - perror("socket"); - return -1; + goto err; } - qemu_set_nonblock(fd); - connected = 0; - for(;;) { - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - if (errno == EINTR || errno == EWOULDBLOCK) { - /* continue */ - } else if (errno == EINPROGRESS || - errno == EALREADY || - errno == EINVAL) { - break; - } else { - perror("connect"); - closesocket(fd); - return -1; - } - } else { - connected = 1; - break; - } - } - s = net_socket_fd_init(peer, model, name, fd, connected); - if (!s) - return -1; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; + +err: + error_report_err(local_error); + socket_connect_data_free(c); + return -1; } static int net_socket_mcast_init(NetClientState *peer, diff --git a/qemu-char.c b/qemu-char.c index 7fa87a8b6e..8826419d7d 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1230,6 +1230,9 @@ static CharDriverState *qemu_chr_open_stdio(const char *id, sigaction(SIGCONT, &act, NULL); chr = qemu_chr_open_fd(0, 1, common, errp); + if (!chr) { + return NULL; + } chr->chr_close = qemu_chr_close_stdio; chr->chr_set_echo = qemu_chr_set_echo_stdio; if (opts->has_signal) { @@ -1686,6 +1689,9 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd, tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd, backend, errp); + if (!chr) { + return NULL; + } chr->chr_ioctl = tty_serial_ioctl; chr->chr_close = qemu_chr_close_tty; return chr; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index bb3ffda244..58e43b6f4b 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1035,6 +1035,9 @@ typedef struct CPUX86State { uint64_t tsc; uint64_t tsc_adjust; uint64_t tsc_deadline; + uint64_t tsc_aux; + + uint64_t xcr0; uint64_t mcg_status; uint64_t msr_ia32_misc_enable; @@ -1051,6 +1054,8 @@ typedef struct CPUX86State { uint64_t pat; uint32_t smbase; + uint32_t pkru; + /* End of state preserved by INIT (dummy marker). */ struct {} end_init_save; @@ -1135,20 +1140,15 @@ typedef struct CPUX86State { uint64_t mcg_ctl; uint64_t mcg_ext_ctl; uint64_t mce_banks[MCE_BANKS_DEF*4]; - - uint64_t tsc_aux; + uint64_t xstate_bv; /* vmstate */ uint16_t fpus_vmstate; uint16_t fptag_vmstate; uint16_t fpregs_format_vmstate; - uint64_t xstate_bv; - uint64_t xcr0; uint64_t xss; - uint32_t pkru; - TPRAccess tpr_access_type; } CPUX86State; diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 6cbdf17426..fb79f3180d 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -1137,25 +1137,27 @@ static void do_interrupt_real(CPUX86State *env, int intno, int is_int, static void do_interrupt_user(CPUX86State *env, int intno, int is_int, int error_code, target_ulong next_eip) { - SegmentCache *dt; - target_ulong ptr; - int dpl, cpl, shift; - uint32_t e2; + if (is_int) { + SegmentCache *dt; + target_ulong ptr; + int dpl, cpl, shift; + uint32_t e2; - dt = &env->idt; - if (env->hflags & HF_LMA_MASK) { - shift = 4; - } else { - shift = 3; - } - ptr = dt->base + (intno << shift); - e2 = cpu_ldl_kernel(env, ptr + 4); + dt = &env->idt; + if (env->hflags & HF_LMA_MASK) { + shift = 4; + } else { + shift = 3; + } + ptr = dt->base + (intno << shift); + e2 = cpu_ldl_kernel(env, ptr + 4); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privilege if software int */ - if (is_int && dpl < cpl) { - raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privilege if software int */ + if (dpl < cpl) { + raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); + } } /* Since we emulate only user space, we cannot do more than diff --git a/util/bufferiszero.c b/util/bufferiszero.c index abe65f9d88..eb974b7849 100644 --- a/util/bufferiszero.c +++ b/util/bufferiszero.c @@ -26,38 +26,6 @@ #include "qemu/cutils.h" #include "qemu/bswap.h" - -/* vector definitions */ - -extern void link_error(void); - -#define ACCEL_BUFFER_ZERO(NAME, SIZE, VECTYPE, NONZERO) \ -static bool NAME(const void *buf, size_t len) \ -{ \ - const void *end = buf + len; \ - do { \ - const VECTYPE *p = buf; \ - VECTYPE t; \ - __builtin_prefetch(buf + SIZE); \ - barrier(); \ - if (SIZE == sizeof(VECTYPE) * 4) { \ - t = (p[0] | p[1]) | (p[2] | p[3]); \ - } else if (SIZE == sizeof(VECTYPE) * 8) { \ - t = p[0] | p[1]; \ - t |= p[2] | p[3]; \ - t |= p[4] | p[5]; \ - t |= p[6] | p[7]; \ - } else { \ - link_error(); \ - } \ - if (unlikely(NONZERO(t))) { \ - return false; \ - } \ - buf += SIZE; \ - } while (buf < end); \ - return true; \ -} - static bool buffer_zero_int(const void *buf, size_t len) { @@ -96,47 +64,174 @@ buffer_zero_int(const void *buf, size_t len) } } -#if defined(CONFIG_AVX2_OPT) || (defined(CONFIG_CPUID_H) && defined(__SSE2__)) -#include - +#if defined(CONFIG_AVX2_OPT) || defined(__SSE2__) /* Do not use push_options pragmas unnecessarily, because clang * does not support them. */ -#ifndef __SSE2__ +#ifdef CONFIG_AVX2_OPT #pragma GCC push_options #pragma GCC target("sse2") #endif #include -#define SSE2_NONZERO(X) \ - (_mm_movemask_epi8(_mm_cmpeq_epi8((X), _mm_setzero_si128())) != 0xFFFF) -ACCEL_BUFFER_ZERO(buffer_zero_sse2, 64, __m128i, SSE2_NONZERO) -#ifndef __SSE2__ + +/* Note that each of these vectorized functions require len >= 64. */ + +static bool +buffer_zero_sse2(const void *buf, size_t len) +{ + __m128i t = _mm_loadu_si128(buf); + __m128i *p = (__m128i *)(((uintptr_t)buf + 5 * 16) & -16); + __m128i *e = (__m128i *)(((uintptr_t)buf + len) & -16); + __m128i zero = _mm_setzero_si128(); + + /* Loop over 16-byte aligned blocks of 64. */ + while (likely(p <= e)) { + __builtin_prefetch(p); + t = _mm_cmpeq_epi8(t, zero); + if (unlikely(_mm_movemask_epi8(t) != 0xFFFF)) { + return false; + } + t = p[-4] | p[-3] | p[-2] | p[-1]; + p += 4; + } + + /* Finish the aligned tail. */ + t |= e[-3]; + t |= e[-2]; + t |= e[-1]; + + /* Finish the unaligned tail. */ + t |= _mm_loadu_si128(buf + len - 16); + + return _mm_movemask_epi8(_mm_cmpeq_epi8(t, zero)) == 0xFFFF; +} +#ifdef CONFIG_AVX2_OPT #pragma GCC pop_options #endif #ifdef CONFIG_AVX2_OPT +/* Note that due to restrictions/bugs wrt __builtin functions in gcc <= 4.8, + * the includes have to be within the corresponding push_options region, and + * therefore the regions themselves have to be ordered with increasing ISA. + */ #pragma GCC push_options #pragma GCC target("sse4") #include -#define SSE4_NONZERO(X) !_mm_testz_si128((X), (X)) -ACCEL_BUFFER_ZERO(buffer_zero_sse4, 64, __m128i, SSE4_NONZERO) -#pragma GCC pop_options +static bool +buffer_zero_sse4(const void *buf, size_t len) +{ + __m128i t = _mm_loadu_si128(buf); + __m128i *p = (__m128i *)(((uintptr_t)buf + 5 * 16) & -16); + __m128i *e = (__m128i *)(((uintptr_t)buf + len) & -16); + + /* Loop over 16-byte aligned blocks of 64. */ + while (likely(p <= e)) { + __builtin_prefetch(p); + if (unlikely(!_mm_testz_si128(t, t))) { + return false; + } + t = p[-4] | p[-3] | p[-2] | p[-1]; + p += 4; + } + + /* Finish the aligned tail. */ + t |= e[-3]; + t |= e[-2]; + t |= e[-1]; + + /* Finish the unaligned tail. */ + t |= _mm_loadu_si128(buf + len - 16); + + return _mm_testz_si128(t, t); +} + +#pragma GCC pop_options #pragma GCC push_options #pragma GCC target("avx2") #include -#define AVX2_NONZERO(X) !_mm256_testz_si256((X), (X)) -ACCEL_BUFFER_ZERO(buffer_zero_avx2, 128, __m256i, AVX2_NONZERO) + +static bool +buffer_zero_avx2(const void *buf, size_t len) +{ + /* Begin with an unaligned head of 32 bytes. */ + __m256i t = _mm256_loadu_si256(buf); + __m256i *p = (__m256i *)(((uintptr_t)buf + 5 * 32) & -32); + __m256i *e = (__m256i *)(((uintptr_t)buf + len) & -32); + + if (likely(p <= e)) { + /* Loop over 32-byte aligned blocks of 128. */ + do { + __builtin_prefetch(p); + if (unlikely(!_mm256_testz_si256(t, t))) { + return false; + } + t = p[-4] | p[-3] | p[-2] | p[-1]; + p += 4; + } while (p <= e); + } else { + t |= _mm256_loadu_si256(buf + 32); + if (len <= 128) { + goto last2; + } + } + + /* Finish the last block of 128 unaligned. */ + t |= _mm256_loadu_si256(buf + len - 4 * 32); + t |= _mm256_loadu_si256(buf + len - 3 * 32); + last2: + t |= _mm256_loadu_si256(buf + len - 2 * 32); + t |= _mm256_loadu_si256(buf + len - 1 * 32); + + return _mm256_testz_si256(t, t); +} #pragma GCC pop_options +#endif /* CONFIG_AVX2_OPT */ + +/* Note that for test_buffer_is_zero_next_accel, the most preferred + * ISA must have the least significant bit. + */ +#define CACHE_AVX2 1 +#define CACHE_SSE4 2 +#define CACHE_SSE2 4 + +/* Make sure that these variables are appropriately initialized when + * SSE2 is enabled on the compiler command-line, but the compiler is + * too old to support . + */ +#ifdef CONFIG_AVX2_OPT +# define INIT_CACHE 0 +# define INIT_ACCEL buffer_zero_int +#else +# ifndef __SSE2__ +# error "ISA selection confusion" +# endif +# define INIT_CACHE CACHE_SSE2 +# define INIT_ACCEL buffer_zero_sse2 #endif -#define CACHE_AVX2 2 -#define CACHE_AVX1 4 -#define CACHE_SSE4 8 -#define CACHE_SSE2 16 +static unsigned cpuid_cache = INIT_CACHE; +static bool (*buffer_accel)(const void *, size_t) = INIT_ACCEL; -static unsigned cpuid_cache; +static void init_accel(unsigned cache) +{ + bool (*fn)(const void *, size_t) = buffer_zero_int; + if (cache & CACHE_SSE2) { + fn = buffer_zero_sse2; + } +#ifdef CONFIG_AVX2_OPT + if (cache & CACHE_SSE4) { + fn = buffer_zero_sse4; + } + if (cache & CACHE_AVX2) { + fn = buffer_zero_avx2; + } +#endif + buffer_accel = fn; +} +#ifdef CONFIG_AVX2_OPT +#include static void __attribute__((constructor)) init_cpuid_cache(void) { int max = __get_cpuid_max(0, NULL); @@ -154,24 +249,21 @@ static void __attribute__((constructor)) init_cpuid_cache(void) } /* We must check that AVX is not just available, but usable. */ - if ((c & bit_OSXSAVE) && (c & bit_AVX)) { - __asm("xgetbv" : "=a"(a), "=d"(d) : "c"(0)); - if ((a & 6) == 6) { - cache |= CACHE_AVX1; - if (max >= 7) { - __cpuid_count(7, 0, a, b, c, d); - if (b & bit_AVX2) { - cache |= CACHE_AVX2; - } - } + if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { + int bv; + __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); + __cpuid_count(7, 0, a, b, c, d); + if ((bv & 6) == 6 && (b & bit_AVX2)) { + cache |= CACHE_AVX2; } } #endif } cpuid_cache = cache; + init_accel(cache); } +#endif /* CONFIG_AVX2_OPT */ -#define HAVE_NEXT_ACCEL bool test_buffer_is_zero_next_accel(void) { /* If no bits set, we just tested buffer_zero_int, and there @@ -181,31 +273,20 @@ bool test_buffer_is_zero_next_accel(void) } /* Disable the accelerator we used before and select a new one. */ cpuid_cache &= cpuid_cache - 1; + init_accel(cpuid_cache); return true; } static bool select_accel_fn(const void *buf, size_t len) { - uintptr_t ibuf = (uintptr_t)buf; -#ifdef CONFIG_AVX2_OPT - if (len % 128 == 0 && ibuf % 32 == 0 && (cpuid_cache & CACHE_AVX2)) { - return buffer_zero_avx2(buf, len); - } - if (len % 64 == 0 && ibuf % 16 == 0 && (cpuid_cache & CACHE_SSE4)) { - return buffer_zero_sse4(buf, len); - } -#endif - if (len % 64 == 0 && ibuf % 16 == 0 && (cpuid_cache & CACHE_SSE2)) { - return buffer_zero_sse2(buf, len); + if (likely(len >= 64)) { + return buffer_accel(buf, len); } return buffer_zero_int(buf, len); } #else #define select_accel_fn buffer_zero_int -#endif - -#ifndef HAVE_NEXT_ACCEL bool test_buffer_is_zero_next_accel(void) { return false; diff --git a/util/log.c b/util/log.c index 54b54e868a..e077340ae1 100644 --- a/util/log.c +++ b/util/log.c @@ -275,53 +275,42 @@ const QEMULogItem qemu_log_items[] = { { 0, NULL, NULL }, }; -static int cmp1(const char *s1, int n, const char *s2) -{ - if (strlen(s2) != n) { - return 0; - } - return memcmp(s1, s2, n) == 0; -} - /* takes a comma separated list of log masks. Return 0 if error. */ int qemu_str_to_log_mask(const char *str) { const QEMULogItem *item; - int mask; - const char *p, *p1; + int mask = 0; + char **parts = g_strsplit(str, ",", 0); + char **tmp; - p = str; - mask = 0; - for (;;) { - p1 = strchr(p, ','); - if (!p1) { - p1 = p + strlen(p); - } - if (cmp1(p,p1-p,"all")) { + for (tmp = parts; tmp && *tmp; tmp++) { + if (g_str_equal(*tmp, "all")) { for (item = qemu_log_items; item->mask != 0; item++) { mask |= item->mask; } #ifdef CONFIG_TRACE_LOG - } else if (strncmp(p, "trace:", 6) == 0 && p + 6 != p1) { - trace_enable_events(p + 6); + } else if (g_str_has_prefix(*tmp, "trace:") && (*tmp)[6] != '\0') { + trace_enable_events((*tmp) + 6); mask |= LOG_TRACE; #endif } else { for (item = qemu_log_items; item->mask != 0; item++) { - if (cmp1(p, p1 - p, item->name)) { + if (g_str_equal(*tmp, item->name)) { goto found; } } - return 0; + goto error; found: mask |= item->mask; } - if (*p1 != ',') { - break; - } - p = p1 + 1; } + + g_strfreev(parts); return mask; + + error: + g_strfreev(parts); + return 0; } void qemu_print_log_usage(FILE *f)