From c6fcb0e201ad296a9c0f587486830d9508094efb Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 3 Feb 2017 15:18:16 +0800 Subject: [PATCH 01/23] kvm/ioapic: dump real object instead of a fake one When we do "info ioapic" for kvm ioapic, we were building up a temporary ioapic object. Let's fetch the real one and update correspond to the real object as well. This fixes printing uninitialized version field in ioapic_print_redtbl(). Reported-by: Peter Maydell Suggested-by: Paolo Bonzini Signed-off-by: Peter Xu Message-Id: <1486106298-3699-2-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i386/kvm/ioapic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index 8eb2c7a70f..716d59aa22 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -114,11 +114,11 @@ static void kvm_ioapic_put(IOAPICCommonState *s) void kvm_ioapic_dump_state(Monitor *mon, const QDict *qdict) { - IOAPICCommonState s; + IOAPICCommonState *s = IOAPIC_COMMON(object_resolve_path("ioapic", NULL)); - kvm_ioapic_get(&s); - - ioapic_print_redtbl(mon, &s); + assert(s); + kvm_ioapic_get(s); + ioapic_print_redtbl(mon, s); } static void kvm_ioapic_reset(DeviceState *dev) From 8d5516be1224468b5dbc141fbc7644bbd3a96183 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 3 Feb 2017 15:18:17 +0800 Subject: [PATCH 02/23] ioapic: fix error report value of def version It should be 0x20, rather than 0x11. Signed-off-by: Peter Xu Message-Id: <1486106298-3699-3-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/intc/ioapic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 9047b8950a..37c4386ae3 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -408,13 +408,15 @@ static void ioapic_machine_done_notify(Notifier *notifier, void *data) #endif } +#define IOAPIC_VER_DEF 0x20 + static void ioapic_realize(DeviceState *dev, Error **errp) { IOAPICCommonState *s = IOAPIC_COMMON(dev); if (s->version != 0x11 && s->version != 0x20) { error_report("IOAPIC only supports version 0x11 or 0x20 " - "(default: 0x11)."); + "(default: 0x%x).", IOAPIC_VER_DEF); exit(1); } @@ -429,7 +431,7 @@ static void ioapic_realize(DeviceState *dev, Error **errp) } static Property ioapic_properties[] = { - DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x20), + DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF), DEFINE_PROP_END_OF_LIST(), }; From b7a4104b73cd02cd014c12e467bc599b69421c7b Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 3 Feb 2017 15:18:18 +0800 Subject: [PATCH 03/23] kvm/ioapic: correct kvm ioapic version Signed-off-by: Peter Xu Message-Id: <1486106298-3699-4-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i386/kvm/ioapic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index 716d59aa22..98ca480792 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -143,6 +143,11 @@ static void kvm_ioapic_realize(DeviceState *dev, Error **errp) IOAPICCommonState *s = IOAPIC_COMMON(dev); memory_region_init_reservation(&s->io_memory, NULL, "kvm-ioapic", 0x1000); + /* + * KVM ioapic only supports 0x11 now. This will only be used when + * we want to dump ioapic version. + */ + s->version = 0x11; qdev_init_gpio_in(dev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS); } From a3fd46152ed27e795871e9e5e73ef9c90a16e25e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 30 Jan 2017 15:11:19 -0500 Subject: [PATCH 04/23] test-vmstate: remove yield_until_fd_readable The function is not needed anymore now that migration is built on top of QIOChannel. Signed-off-by: Paolo Bonzini --- tests/test-vmstate.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index d0dd390006..39f338a4c4 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -33,17 +33,6 @@ static char temp_file[] = "/tmp/vmst.test.XXXXXX"; static int temp_fd; -/* Fake yield_until_fd_readable() implementation so we don't have to pull the - * coroutine code as dependency. - */ -void yield_until_fd_readable(int fd) -{ - fd_set fds; - FD_ZERO(&fds); - FD_SET(fd, &fds); - select(fd + 1, &fds, NULL, NULL, NULL); -} - /* Duplicate temp_fd and seek to the beginning of the file */ static QEMUFile *open_test_file(bool write) From b0a335e351103bf92f3f9d0bd5759311be8156ac Mon Sep 17 00:00:00 2001 From: Anton Nefedov Date: Thu, 2 Feb 2017 17:26:29 +0300 Subject: [PATCH 05/23] qemu-char: socket backend: disconnect on write error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Socket backend read handler should normally perform a disconnect, however the read handler may not get a chance to run if the frontend is not ready (qemu_chr_be_can_write() == 0). This means that in virtio-serial frontend case if - the host has disconnected (giving EPIPE on socket write) - and the guest has disconnected (-> frontend not ready -> backend will not read) - and there is still data (frontend->backend) to flush (has to be a really tricky timing but nevertheless, we have observed the case in production) This results in virtio-serial trying to flush this data continiously forming a busy loop. Solution: react on write error in the socket write handler. errno is not reliable after qio_channel_writev_full(), so we may not get the exact EPIPE, so disconnect on any error but QIO_CHANNEL_ERR_BLOCK which io_channel_send_full() converts to errno EAGAIN. We must not disconnect right away though, there still may be data to read (see 4bf1cb0). Signed-off-by: Anton Nefedov Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Daniel P. Berrange CC: Marc-André Lureau Message-Id: <1486045589-8074-1-git-send-email-den@openvz.org> Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 4068dc5e52..865c52762e 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -97,6 +97,9 @@ static gboolean tcp_chr_accept(QIOChannel *chan, GIOCondition cond, void *opaque); +static int tcp_chr_read_poll(void *opaque); +static void tcp_chr_disconnect(Chardev *chr); + /* Called with chr_write_lock held. */ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len) { @@ -114,6 +117,13 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len) s->write_msgfds_num = 0; } + if (ret < 0 && errno != EAGAIN) { + if (tcp_chr_read_poll(chr) <= 0) { + tcp_chr_disconnect(chr); + return len; + } /* else let the read handler finish it properly */ + } + return ret; } else { /* XXX: indicate an error ? */ From f65e821262029ee30c6b228e80ddeb86acdf7ff0 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Tue, 31 Jan 2017 14:40:54 +0300 Subject: [PATCH 06/23] apic: reset apic_delivered global variable on machine reset This patch adds call to apic_reset_irq_delivered when the virtual machine is reset. Signed-off-by: Pavel Dovgalyuk Message-Id: <20170131114054.276.62201.stgit@PASHA-ISP> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/intc/apic_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 6ce8ef744a..7a6e771ed1 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -251,6 +251,8 @@ static void apic_reset_common(DeviceState *dev) s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE; s->id = s->initial_apic_id; + apic_reset_irq_delivered(); + s->vapic_paddr = 0; info->vapic_base_update(s); From 1c64fdbc8177058802df205f5d7cd65edafa59a8 Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Tue, 31 Jan 2017 05:45:29 -0800 Subject: [PATCH 07/23] char: drop data written to a disconnected pty When a serial port writes data to a pty that's disconnected, drop the data and return the length dropped. This avoids triggering pointless retries in callers like the 16550A serial_xmit(), and causes qemu_chr_fe_write() to write all data to the log file, rather than logging only while a pty client like virsh console happens to be connected. Signed-off-by: Ed Swierk Message-Id: <1485870329-79428-1-git-send-email-eswierk@skyportsystems.com> Signed-off-by: Paolo Bonzini --- chardev/char-pty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chardev/char-pty.c b/chardev/char-pty.c index 27eb85f505..ecf2c7a5c4 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -129,7 +129,7 @@ static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len) /* guest sends data, check for (re-)connect */ pty_chr_update_read_handler_locked(chr); if (!s->connected) { - return 0; + return len; } } return io_channel_send(s->ioc, buf, len); From 2d76e82395979b44e055b69b7e453f43c5c060cf Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 14 Feb 2017 18:07:47 +0100 Subject: [PATCH 08/23] move vm_start to cpus.c This patch: * moves vm_start to cpus.c. * exports qemu_vmstop_requested, since it's needed by vm_start. * extracts vm_prepare_start from vm_start; it does what vm_start did, except restarting the cpus. * vm_start now calls vm_prepare_start and then restarts the cpus. Signed-off-by: Claudio Imbrenda Message-Id: <1487092068-16562-2-git-send-email-imbrenda@linux.vnet.ibm.com> Signed-off-by: Paolo Bonzini --- cpus.c | 42 +++++++++++++++++++++++++++++++++++++++++ include/sysemu/sysemu.h | 2 ++ vl.c | 30 +---------------------------- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/cpus.c b/cpus.c index 71a82e5004..0bcb5b50b6 100644 --- a/cpus.c +++ b/cpus.c @@ -1578,6 +1578,48 @@ int vm_stop(RunState state) return do_vm_stop(state); } +/** + * Prepare for (re)starting the VM. + * Returns -1 if the vCPUs are not to be restarted (e.g. if they are already + * running or in case of an error condition), 0 otherwise. + */ +int vm_prepare_start(void) +{ + RunState requested; + int res = 0; + + qemu_vmstop_requested(&requested); + if (runstate_is_running() && requested == RUN_STATE__MAX) { + return -1; + } + + /* Ensure that a STOP/RESUME pair of events is emitted if a + * vmstop request was pending. The BLOCK_IO_ERROR event, for + * example, according to documentation is always followed by + * the STOP event. + */ + if (runstate_is_running()) { + qapi_event_send_stop(&error_abort); + res = -1; + } else { + replay_enable_events(); + cpu_enable_ticks(); + runstate_set(RUN_STATE_RUNNING); + vm_state_notify(1, RUN_STATE_RUNNING); + } + + /* We are sending this now, but the CPUs will be resumed shortly later */ + qapi_event_send_resume(&error_abort); + return res; +} + +void vm_start(void) +{ + if (!vm_prepare_start()) { + resume_all_vcpus(); + } +} + /* does a state transition even if the VM is already stopped, current state is forgotten forever */ int vm_stop_force_state(RunState state) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 4d50694930..eda5241d38 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -37,6 +37,7 @@ void vm_state_notify(int running, RunState state); #define VMRESET_REPORT true void vm_start(void); +int vm_prepare_start(void); int vm_stop(RunState state); int vm_stop_force_state(RunState state); @@ -60,6 +61,7 @@ void qemu_register_powerdown_notifier(Notifier *notifier); void qemu_system_debug_request(void); void qemu_system_vmstop_request(RunState reason); void qemu_system_vmstop_request_prepare(void); +bool qemu_vmstop_requested(RunState *r); int qemu_shutdown_requested_get(void); int qemu_reset_requested_get(void); void qemu_system_killed(int signal, pid_t pid); diff --git a/vl.c b/vl.c index b4eaf03734..0d866adce6 100644 --- a/vl.c +++ b/vl.c @@ -724,7 +724,7 @@ StatusInfo *qmp_query_status(Error **errp) return info; } -static bool qemu_vmstop_requested(RunState *r) +bool qemu_vmstop_requested(RunState *r) { qemu_mutex_lock(&vmstop_lock); *r = vmstop_requested; @@ -745,34 +745,6 @@ void qemu_system_vmstop_request(RunState state) qemu_notify_event(); } -void vm_start(void) -{ - RunState requested; - - qemu_vmstop_requested(&requested); - if (runstate_is_running() && requested == RUN_STATE__MAX) { - return; - } - - /* Ensure that a STOP/RESUME pair of events is emitted if a - * vmstop request was pending. The BLOCK_IO_ERROR event, for - * example, according to documentation is always followed by - * the STOP event. - */ - if (runstate_is_running()) { - qapi_event_send_stop(&error_abort); - } else { - replay_enable_events(); - cpu_enable_ticks(); - runstate_set(RUN_STATE_RUNNING); - vm_state_notify(1, RUN_STATE_RUNNING); - resume_all_vcpus(); - } - - qapi_event_send_resume(&error_abort); -} - - /***********************************************************/ /* real time host monotonic timer */ From 544177ad1cfd78a7e1106d9b82b130fd7959efd8 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 14 Feb 2017 18:07:48 +0100 Subject: [PATCH 09/23] gdbstub: Fix vCont behaviour When GDB issues a "vCont", QEMU was not handling it correctly when multiple VCPUs are active. For vCont, for each thread (VCPU), it can be specified whether to single step, continue or stop that thread. The default is to stop a thread. However, when (for example) "vCont;s:2" is issued, all VCPUs continue to run, although all but VCPU nr 2 are to be stopped. This patch completely rewrites the vCont parsing code. Please note that this improvement only works in system emulation mode, when in userspace emulation mode the old behaviour is preserved. Signed-off-by: Claudio Imbrenda Message-Id: <1487092068-16562-3-git-send-email-imbrenda@linux.vnet.ibm.com> Signed-off-by: Paolo Bonzini --- gdbstub.c | 207 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 161 insertions(+), 46 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 755a8e378d..991115361e 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -387,6 +387,60 @@ static inline void gdb_continue(GDBState *s) #endif } +/* + * Resume execution, per CPU actions. For user-mode emulation it's + * equivalent to gdb_continue. + */ +static int gdb_continue_partial(GDBState *s, char *newstates) +{ + CPUState *cpu; + int res = 0; +#ifdef CONFIG_USER_ONLY + /* + * This is not exactly accurate, but it's an improvement compared to the + * previous situation, where only one CPU would be single-stepped. + */ + CPU_FOREACH(cpu) { + if (newstates[cpu->cpu_index] == 's') { + cpu_single_step(cpu, sstep_flags); + } + } + s->running_state = 1; +#else + int flag = 0; + + if (!runstate_needs_reset()) { + if (vm_prepare_start()) { + return 0; + } + + CPU_FOREACH(cpu) { + switch (newstates[cpu->cpu_index]) { + case 0: + case 1: + break; /* nothing to do here */ + case 's': + cpu_single_step(cpu, sstep_flags); + cpu_resume(cpu); + flag = 1; + break; + case 'c': + cpu_resume(cpu); + flag = 1; + break; + default: + res = -1; + break; + } + } + } + if (flag) { + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + } +#endif + return res; +} + static void put_buffer(GDBState *s, const uint8_t *buf, int len) { #ifdef CONFIG_USER_ONLY @@ -785,6 +839,107 @@ static int is_query_packet(const char *p, const char *query, char separator) (p[query_len] == '\0' || p[query_len] == separator); } +/** + * gdb_handle_vcont - Parses and handles a vCont packet. + * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is + * a format error, 0 on success. + */ +static int gdb_handle_vcont(GDBState *s, const char *p) +{ + int res, idx, signal = 0; + char cur_action; + char *newstates; + unsigned long tmp; + CPUState *cpu; +#ifdef CONFIG_USER_ONLY + int max_cpus = 1; /* global variable max_cpus exists only in system mode */ + + CPU_FOREACH(cpu) { + max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus; + } +#endif + /* uninitialised CPUs stay 0 */ + newstates = g_new0(char, max_cpus); + + /* mark valid CPUs with 1 */ + CPU_FOREACH(cpu) { + newstates[cpu->cpu_index] = 1; + } + + /* + * res keeps track of what error we are returning, with -ENOTSUP meaning + * that the command is unknown or unsupported, thus returning an empty + * packet, while -EINVAL and -ERANGE cause an E22 packet, due to invalid, + * or incorrect parameters passed. + */ + res = 0; + while (*p) { + if (*p++ != ';') { + res = -ENOTSUP; + goto out; + } + + cur_action = *p++; + if (cur_action == 'C' || cur_action == 'S') { + cur_action = tolower(cur_action); + res = qemu_strtoul(p + 1, &p, 16, &tmp); + if (res) { + goto out; + } + signal = gdb_signal_to_target(tmp); + } else if (cur_action != 'c' && cur_action != 's') { + /* unknown/invalid/unsupported command */ + res = -ENOTSUP; + goto out; + } + /* thread specification. special values: (none), -1 = all; 0 = any */ + if ((p[0] == ':' && p[1] == '-' && p[2] == '1') || (p[0] != ':')) { + if (*p == ':') { + p += 3; + } + for (idx = 0; idx < max_cpus; idx++) { + if (newstates[idx] == 1) { + newstates[idx] = cur_action; + } + } + } else if (*p == ':') { + p++; + res = qemu_strtoul(p, &p, 16, &tmp); + if (res) { + goto out; + } + idx = tmp; + /* 0 means any thread, so we pick the first valid CPU */ + if (!idx) { + idx = cpu_index(first_cpu); + } + + /* + * If we are in user mode, the thread specified is actually a + * thread id, and not an index. We need to find the actual + * CPU first, and only then we can use its index. + */ + cpu = find_cpu(idx); + /* invalid CPU/thread specified */ + if (!idx || !cpu) { + res = -EINVAL; + goto out; + } + /* only use if no previous match occourred */ + if (newstates[cpu->cpu_index] == 1) { + newstates[cpu->cpu_index] = cur_action; + } + } + } + s->signal = signal; + gdb_continue_partial(s, newstates); + +out: + g_free(newstates); + + return res; +} + static int gdb_handle_packet(GDBState *s, const char *line_buf) { CPUState *cpu; @@ -830,60 +985,20 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) return RS_IDLE; case 'v': if (strncmp(p, "Cont", 4) == 0) { - int res_signal, res_thread; - p += 4; if (*p == '?') { put_packet(s, "vCont;c;C;s;S"); break; } - res = 0; - res_signal = 0; - res_thread = 0; - while (*p) { - int action, signal; - if (*p++ != ';') { - res = 0; - break; - } - action = *p++; - signal = 0; - if (action == 'C' || action == 'S') { - signal = gdb_signal_to_target(strtoul(p, (char **)&p, 16)); - if (signal == -1) { - signal = 0; - } - } else if (action != 'c' && action != 's') { - res = 0; - break; - } - thread = 0; - if (*p == ':') { - thread = strtoull(p+1, (char **)&p, 16); - } - action = tolower(action); - if (res == 0 || (res == 'c' && action == 's')) { - res = action; - res_signal = signal; - res_thread = thread; - } - } + res = gdb_handle_vcont(s, p); + if (res) { - if (res_thread != -1 && res_thread != 0) { - cpu = find_cpu(res_thread); - if (cpu == NULL) { - put_packet(s, "E22"); - break; - } - s->c_cpu = cpu; + if ((res == -EINVAL) || (res == -ERANGE)) { + put_packet(s, "E22"); + break; } - if (res == 's') { - cpu_single_step(s->c_cpu, sstep_flags); - } - s->signal = res_signal; - gdb_continue(s); - return RS_IDLE; + goto unknown_command; } break; } else { From d9ff1d35c5242d73e7923ae259e065739090db54 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sat, 28 Jan 2017 07:56:22 +0100 Subject: [PATCH 10/23] hw/char/mcf_uart: QOMify the ColdFire UART Use type_init() etc. to adapt the ColdFire UART to the latest QEMU device conventions. Signed-off-by: Thomas Huth Message-Id: <1485586582-6490-1-git-send-email-huth@tuxfamily.org> Signed-off-by: Paolo Bonzini --- hw/char/mcf_uart.c | 102 +++++++++++++++++++++++++++++++----------- hw/m68k/mcf5208.c | 6 +-- include/hw/m68k/mcf.h | 6 +-- 3 files changed, 81 insertions(+), 33 deletions(-) diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c index 80c380e077..e69672f4e9 100644 --- a/hw/char/mcf_uart.c +++ b/hw/char/mcf_uart.c @@ -7,12 +7,15 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" +#include "hw/sysbus.h" #include "hw/m68k/mcf.h" #include "sysemu/char.h" #include "exec/address-spaces.h" #include "qapi/error.h" typedef struct { + SysBusDevice parent_obj; + MemoryRegion iomem; uint8_t mr[2]; uint8_t sr; @@ -30,6 +33,9 @@ typedef struct { CharBackend chr; } mcf_uart_state; +#define TYPE_MCF_UART "mcf-uart" +#define MCF_UART(obj) OBJECT_CHECK(mcf_uart_state, (obj), TYPE_MCF_UART) + /* UART Status Register bits. */ #define MCF_UART_RxRDY 0x01 #define MCF_UART_FFULL 0x02 @@ -220,8 +226,10 @@ void mcf_uart_write(void *opaque, hwaddr addr, mcf_uart_update(s); } -static void mcf_uart_reset(mcf_uart_state *s) +static void mcf_uart_reset(DeviceState *dev) { + mcf_uart_state *s = MCF_UART(dev); + s->fifo_len = 0; s->mr[0] = 0; s->mr[1] = 0; @@ -275,36 +283,80 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) mcf_uart_push_byte(s, buf[0]); } -void *mcf_uart_init(qemu_irq irq, Chardev *chr) -{ - mcf_uart_state *s; - - s = g_malloc0(sizeof(mcf_uart_state)); - s->irq = irq; - if (chr) { - qemu_chr_fe_init(&s->chr, chr, &error_abort); - qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, - mcf_uart_receive, mcf_uart_event, - s, NULL, true); - } - mcf_uart_reset(s); - return s; -} - static const MemoryRegionOps mcf_uart_ops = { .read = mcf_uart_read, .write = mcf_uart_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -void mcf_uart_mm_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, - Chardev *chr) +static void mcf_uart_instance_init(Object *obj) { - mcf_uart_state *s; + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + mcf_uart_state *s = MCF_UART(dev); - s = mcf_uart_init(irq, chr); - memory_region_init_io(&s->iomem, NULL, &mcf_uart_ops, s, "uart", 0x40); - memory_region_add_subregion(sysmem, base, &s->iomem); + memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40); + sysbus_init_mmio(dev, &s->iomem); + + sysbus_init_irq(dev, &s->irq); +} + +static void mcf_uart_realize(DeviceState *dev, Error **errp) +{ + mcf_uart_state *s = MCF_UART(dev); + + qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive, + mcf_uart_event, s, NULL, true); +} + +static Property mcf_uart_properties[] = { + DEFINE_PROP_CHR("chardev", mcf_uart_state, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void mcf_uart_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = mcf_uart_realize; + dc->reset = mcf_uart_reset; + dc->props = mcf_uart_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static const TypeInfo mcf_uart_info = { + .name = TYPE_MCF_UART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mcf_uart_state), + .instance_init = mcf_uart_instance_init, + .class_init = mcf_uart_class_init, +}; + +static void mcf_uart_register(void) +{ + type_register_static(&mcf_uart_info); +} + +type_init(mcf_uart_register) + +void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv) +{ + DeviceState *dev; + + dev = qdev_create(NULL, TYPE_MCF_UART); + if (chrdrv) { + qdev_prop_set_chr(dev, "chardev", chrdrv); + } + qdev_init_nofail(dev); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); + + return dev; +} + +void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chrdrv) +{ + DeviceState *dev; + + dev = mcf_uart_init(irq, chrdrv); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); } diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index bad1d332ed..656351834e 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -255,9 +255,9 @@ static void mcf5208evb_init(MachineState *machine) /* Internal peripherals. */ pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu); - mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]); - mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]); - mcf_uart_mm_init(address_space_mem, 0xfc068000, pic[28], serial_hds[2]); + mcf_uart_mm_init(0xfc060000, pic[26], serial_hds[0]); + mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]); + mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]); mcf5208_sys_init(address_space_mem, pic); diff --git a/include/hw/m68k/mcf.h b/include/hw/m68k/mcf.h index 9a0bcfa0f4..0db49c5e60 100644 --- a/include/hw/m68k/mcf.h +++ b/include/hw/m68k/mcf.h @@ -4,17 +4,13 @@ #include "target/m68k/cpu-qom.h" -struct MemoryRegion; - /* mcf_uart.c */ uint64_t mcf_uart_read(void *opaque, hwaddr addr, unsigned size); void mcf_uart_write(void *opaque, hwaddr addr, uint64_t val, unsigned size); void *mcf_uart_init(qemu_irq irq, Chardev *chr); -void mcf_uart_mm_init(struct MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, Chardev *chr); +void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chr); /* mcf_intc.c */ qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem, From 43d70ddf9f96b3ad037abe4d5f9f2768196b8c92 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 29 Jan 2017 12:00:59 +0100 Subject: [PATCH 11/23] cpu-exec: fix icount out-of-bounds access When icount is active, tb_add_jump is surprisingly called with an out of bounds basic block index. I have no idea how that can work, but it does not seem like a good idea. Clear *last_tb for all TB_EXIT_ICOUNT_EXPIRED cases, even when all you have to do is refill icount_extra. Signed-off-by: Paolo Bonzini --- cpu-exec.c | 7 ++++--- include/exec/exec-all.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 57583f16a0..1f7d217f30 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -542,7 +542,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, trace_exec_tb(tb, tb->pc); ret = cpu_tb_exec(cpu, tb); - *last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK); + tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK); *tb_exit = ret & TB_EXIT_MASK; switch (*tb_exit) { case TB_EXIT_REQUESTED: @@ -566,6 +566,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, abort(); #else int insns_left = cpu->icount_decr.u32; + *last_tb = NULL; if (cpu->icount_extra && insns_left >= 0) { /* Refill decrementer and continue execution. */ cpu->icount_extra += insns_left; @@ -575,17 +576,17 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, } else { if (insns_left > 0) { /* Execute remaining instructions. */ - cpu_exec_nocache(cpu, insns_left, *last_tb, false); + cpu_exec_nocache(cpu, insns_left, tb, false); align_clocks(sc, cpu); } cpu->exception_index = EXCP_INTERRUPT; - *last_tb = NULL; cpu_loop_exit(cpu); } break; #endif } default: + *last_tb = tb; break; } } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index bbc9478a50..21ab7bf3fd 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -318,6 +318,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, static inline void tb_add_jump(TranslationBlock *tb, int n, TranslationBlock *tb_next) { + assert(n < ARRAY_SIZE(tb->jmp_list_next)); if (tb->jmp_list_next[n]) { /* Another thread has already done this while we were * outside of the lock; nothing to do in this case */ From a70fe14b7dddcb944fbd6c9f3739cd3a22089af5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 29 Jan 2017 12:15:15 +0100 Subject: [PATCH 12/23] cpu-exec: tighten barrier on TCG_EXIT_REQUESTED This seems to have worked just fine so far on weakly-ordered architectures, but I don't see anything that prevents the reordering from: store 1 to exit_request store 1 to tcg_exit_req load tcg_exit_req store 0 to tcg_exit_req load exit_request store 0 to exit_request store 1 to exit_request store 1 to tcg_exit_req to this: store 1 to exit_request store 1 to tcg_exit_req load tcg_exit_req load exit_request store 1 to exit_request store 1 to tcg_exit_req store 0 to tcg_exit_req store 0 to exit_request therefore losing a request. It's possible that other memory barriers (e.g. in rcu_read_unlock) are hiding it, but better safe than sorry. Signed-off-by: Paolo Bonzini --- cpu-exec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 1f7d217f30..d50625bf97 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -552,11 +552,11 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, * have set something else (eg exit_request or * interrupt_request) which we will handle * next time around the loop. But we need to - * ensure the tcg_exit_req read in generated code + * ensure the zeroing of tcg_exit_req (see cpu_tb_exec) * comes before the next read of cpu->exit_request * or cpu->interrupt_request. */ - smp_rmb(); + smp_mb(); *last_tb = NULL; break; case TB_EXIT_ICOUNT_EXPIRED: From 209b71b60ef3341246038e1c926c3b704969cdd3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 Jan 2017 10:57:18 +0100 Subject: [PATCH 13/23] cpu-exec: avoid cpu_loop_exit in cpu_handle_interrupt The siglongjmp goes straight back to the beginning of cpu_exec's outermost loop. We do not need a siglongjmp, we can simply leave the inner TB execution loop. Signed-off-by: Paolo Bonzini --- cpu-exec.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index d50625bf97..ed2fbc6ed2 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -461,7 +461,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) return false; } -static inline void cpu_handle_interrupt(CPUState *cpu, +static inline bool cpu_handle_interrupt(CPUState *cpu, TranslationBlock **last_tb) { CPUClass *cc = CPU_GET_CLASS(cpu); @@ -475,7 +475,7 @@ static inline void cpu_handle_interrupt(CPUState *cpu, if (interrupt_request & CPU_INTERRUPT_DEBUG) { cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG; cpu->exception_index = EXCP_DEBUG; - cpu_loop_exit(cpu); + return true; } if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) { /* Do nothing */ @@ -484,7 +484,7 @@ static inline void cpu_handle_interrupt(CPUState *cpu, cpu->interrupt_request &= ~CPU_INTERRUPT_HALT; cpu->halted = 1; cpu->exception_index = EXCP_HLT; - cpu_loop_exit(cpu); + return true; } #if defined(TARGET_I386) else if (interrupt_request & CPU_INTERRUPT_INIT) { @@ -494,13 +494,13 @@ static inline void cpu_handle_interrupt(CPUState *cpu, cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0); do_cpu_init(x86_cpu); cpu->exception_index = EXCP_HALTED; - cpu_loop_exit(cpu); + return true; } #else else if (interrupt_request & CPU_INTERRUPT_RESET) { replay_interrupt(); cpu_reset(cpu); - cpu_loop_exit(cpu); + return true; } #endif /* The target hook has 3 exit conditions: @@ -526,8 +526,10 @@ static inline void cpu_handle_interrupt(CPUState *cpu, if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) { atomic_set(&cpu->exit_request, 0); cpu->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(cpu); + return true; } + + return false; } static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, @@ -625,7 +627,7 @@ int cpu_exec(CPUState *cpu) for(;;) { /* prepare setjmp context for exception handling */ if (sigsetjmp(cpu->jmp_env, 0) == 0) { - TranslationBlock *tb, *last_tb = NULL; + TranslationBlock *last_tb = NULL; int tb_exit = 0; /* if an exception is pending, we execute it here */ @@ -633,14 +635,13 @@ int cpu_exec(CPUState *cpu) break; } - for(;;) { - cpu_handle_interrupt(cpu, &last_tb); - tb = tb_find(cpu, last_tb, tb_exit); + while (!cpu_handle_interrupt(cpu, &last_tb)) { + TranslationBlock *tb = tb_find(cpu, last_tb, tb_exit); cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc); /* Try to align the host and virtual clocks if the guest is in advance */ align_clocks(&sc, cpu); - } /* for(;;) */ + } } else { #if defined(__clang__) || !QEMU_GNUC_PREREQ(4, 6) /* Some compilers wrongly smash all local variables after From a42cf3f3f266a97ceb13e8b99bc7b13f7bf4192a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 Jan 2017 11:01:00 +0100 Subject: [PATCH 14/23] cpu-exec: avoid repeated sigsetjmp on interrupts The sigsetjmp only needs to be prepared once for the whole execution of cpu_exec. This patch takes care of the "== 0" side, using a nested loop so that cpu_handle_interrupt goes straight back to cpu_handle_exception without doing another sigsetjmp. Signed-off-by: Paolo Bonzini --- cpu-exec.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index ed2fbc6ed2..865015cd53 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -627,21 +627,21 @@ int cpu_exec(CPUState *cpu) for(;;) { /* prepare setjmp context for exception handling */ if (sigsetjmp(cpu->jmp_env, 0) == 0) { - TranslationBlock *last_tb = NULL; - int tb_exit = 0; - /* if an exception is pending, we execute it here */ - if (cpu_handle_exception(cpu, &ret)) { - break; - } + while (!cpu_handle_exception(cpu, &ret)) { + TranslationBlock *last_tb = NULL; + int tb_exit = 0; - while (!cpu_handle_interrupt(cpu, &last_tb)) { - TranslationBlock *tb = tb_find(cpu, last_tb, tb_exit); - cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc); - /* Try to align the host and virtual clocks - if the guest is in advance */ - align_clocks(&sc, cpu); + while (!cpu_handle_interrupt(cpu, &last_tb)) { + TranslationBlock *tb = tb_find(cpu, last_tb, tb_exit); + cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc); + /* Try to align the host and virtual clocks + if the guest is in advance */ + align_clocks(&sc, cpu); + } } + break; + } else { #if defined(__clang__) || !QEMU_GNUC_PREREQ(4, 6) /* Some compilers wrongly smash all local variables after From 4515e58d60dc3aac53dbd5e53e4c3bec126967d8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 29 Jan 2017 10:55:14 +0100 Subject: [PATCH 15/23] cpu-exec: remove outermost infinite loop Reorganize the sigsetjmp so that the restart case falls through to cpu_handle_exception and the execution loop. Signed-off-by: Paolo Bonzini --- cpu-exec.c | 58 +++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 865015cd53..b8ebb5ccd6 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -624,41 +624,37 @@ int cpu_exec(CPUState *cpu) */ init_delay_params(&sc, cpu); - for(;;) { - /* prepare setjmp context for exception handling */ - if (sigsetjmp(cpu->jmp_env, 0) == 0) { - /* if an exception is pending, we execute it here */ - while (!cpu_handle_exception(cpu, &ret)) { - TranslationBlock *last_tb = NULL; - int tb_exit = 0; - - while (!cpu_handle_interrupt(cpu, &last_tb)) { - TranslationBlock *tb = tb_find(cpu, last_tb, tb_exit); - cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc); - /* Try to align the host and virtual clocks - if the guest is in advance */ - align_clocks(&sc, cpu); - } - } - break; - - } else { + /* prepare setjmp context for exception handling */ + if (sigsetjmp(cpu->jmp_env, 0) != 0) { #if defined(__clang__) || !QEMU_GNUC_PREREQ(4, 6) - /* Some compilers wrongly smash all local variables after - * siglongjmp. There were bug reports for gcc 4.5.0 and clang. - * Reload essential local variables here for those compilers. - * Newer versions of gcc would complain about this code (-Wclobbered). */ - cpu = current_cpu; - cc = CPU_GET_CLASS(cpu); + /* Some compilers wrongly smash all local variables after + * siglongjmp. There were bug reports for gcc 4.5.0 and clang. + * Reload essential local variables here for those compilers. + * Newer versions of gcc would complain about this code (-Wclobbered). */ + cpu = current_cpu; + cc = CPU_GET_CLASS(cpu); #else /* buggy compiler */ - /* Assert that the compiler does not smash local variables. */ - g_assert(cpu == current_cpu); - g_assert(cc == CPU_GET_CLASS(cpu)); + /* Assert that the compiler does not smash local variables. */ + g_assert(cpu == current_cpu); + g_assert(cc == CPU_GET_CLASS(cpu)); #endif /* buggy compiler */ - cpu->can_do_io = 1; - tb_lock_reset(); + cpu->can_do_io = 1; + tb_lock_reset(); + } + + /* if an exception is pending, we execute it here */ + while (!cpu_handle_exception(cpu, &ret)) { + TranslationBlock *last_tb = NULL; + int tb_exit = 0; + + while (!cpu_handle_interrupt(cpu, &last_tb)) { + TranslationBlock *tb = tb_find(cpu, last_tb, tb_exit); + cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc); + /* Try to align the host and virtual clocks + if the guest is in advance */ + align_clocks(&sc, cpu); } - } /* for(;;) */ + } cc->cpu_exec_exit(cpu); rcu_read_unlock(); From 41eeb0e601cbc7ac28fa35547d2426f349ef137d Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Fri, 27 Jan 2017 11:41:54 +0200 Subject: [PATCH 16/23] qemu-doc: Clarify that -vga std is now the default The QEMU manual page states that Cirrus Logic is the default video card if the user doesn't specify any. However this is not true since QEMU 2.2. Signed-off-by: Alberto Garcia Message-Id: <20170127094154.19778-1-berto@igalia.com> Signed-off-by: Paolo Bonzini --- qemu-options.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index ac036b4cbd..5633d3914f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1194,12 +1194,12 @@ Select type of VGA card to emulate. Valid values for @var{type} are Cirrus Logic GD5446 Video card. All Windows versions starting from Windows 95 should recognize and use this graphic card. For optimal performances, use 16 bit color depth in the guest and the host OS. -(This one is the default) +(This card was the default before QEMU 2.2) @item std Standard VGA card with Bochs VBE extensions. If your guest OS supports the VESA 2.0 VBE extensions (e.g. Windows XP) and if you want to use high resolution modes (>= 1280x1024x16) then you should use -this option. +this option. (This card is the default since QEMU 2.2) @item vmware VMWare SVGA-II compatible adapter. Use it if you have sufficiently recent XFree86/XOrg server or Windows guest with a driver for this From a721f53b8f6a30fdc2b6e9fca13ec6c2d762b996 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sat, 4 Feb 2017 10:03:17 +0000 Subject: [PATCH 17/23] qemu-nbd: Implement socket activation. Socket activation (sometimes known as systemd socket activation) allows an Internet superserver to pass a pre-opened listening socket to the process, instead of having qemu-nbd open a socket itself. This is done via the LISTEN_FDS and LISTEN_PID environment variables, and a standard file descriptor range. This change partially implements socket activation for qemu-nbd. If the environment variables are set correctly, then socket activation will happen automatically, otherwise everything works as before. The limitation is that LISTEN_FDS must be 1. Signed-off-by: Richard W.M. Jones Message-Id: <20170204100317.32425-2-rjones@redhat.com> Signed-off-by: Paolo Bonzini --- qemu-nbd.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 9 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index c734f627b4..e4fede641e 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -463,6 +463,135 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) return creds; } +static void setup_address_and_port(const char **address, const char **port) +{ + if (*address == NULL) { + *address = "0.0.0.0"; + } + + if (*port == NULL) { + *port = stringify(NBD_DEFAULT_PORT); + } +} + +#define FIRST_SOCKET_ACTIVATION_FD 3 /* defined by systemd ABI */ + +#ifndef _WIN32 +/* + * Check if socket activation was requested via use of the + * LISTEN_FDS and LISTEN_PID environment variables. + * + * Returns 0 if no socket activation, or the number of FDs. + */ +static unsigned int check_socket_activation(void) +{ + const char *s; + unsigned long pid; + unsigned long nr_fds; + unsigned int i; + int fd; + int err; + + s = getenv("LISTEN_PID"); + if (s == NULL) { + return 0; + } + err = qemu_strtoul(s, NULL, 10, &pid); + if (err) { + if (verbose) { + fprintf(stderr, "malformed %s environment variable (ignored)\n", + "LISTEN_PID"); + } + return 0; + } + if (pid != getpid()) { + if (verbose) { + fprintf(stderr, "%s was not for us (ignored)\n", + "LISTEN_PID"); + } + return 0; + } + + s = getenv("LISTEN_FDS"); + if (s == NULL) { + return 0; + } + err = qemu_strtoul(s, NULL, 10, &nr_fds); + if (err) { + if (verbose) { + fprintf(stderr, "malformed %s environment variable (ignored)\n", + "LISTEN_FDS"); + } + return 0; + } + assert(nr_fds <= UINT_MAX); + + /* A limitation of current qemu-nbd is that it can only listen on + * a single socket. When that limitation is lifted, we can change + * this function to allow LISTEN_FDS > 1, and remove the assertion + * in the main function below. + */ + if (nr_fds > 1) { + error_report("qemu-nbd does not support socket activation with %s > 1", + "LISTEN_FDS"); + exit(EXIT_FAILURE); + } + + /* So these are not passed to any child processes we might start. */ + unsetenv("LISTEN_FDS"); + unsetenv("LISTEN_PID"); + + /* So the file descriptors don't leak into child processes. */ + for (i = 0; i < nr_fds; ++i) { + fd = FIRST_SOCKET_ACTIVATION_FD + i; + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { + /* If we cannot set FD_CLOEXEC then it probably means the file + * descriptor is invalid, so socket activation has gone wrong + * and we should exit. + */ + error_report("Socket activation failed: " + "invalid file descriptor fd = %d: %m", + fd); + exit(EXIT_FAILURE); + } + } + + return (unsigned int) nr_fds; +} + +#else /* !_WIN32 */ +static unsigned int check_socket_activation(void) +{ + return 0; +} +#endif + +/* + * Check socket parameters compatibility when socket activation is used. + */ +static const char *socket_activation_validate_opts(const char *device, + const char *sockpath, + const char *address, + const char *port) +{ + if (device != NULL) { + return "NBD device can't be set when using socket activation"; + } + + if (sockpath != NULL) { + return "Unix socket can't be set when using socket activation"; + } + + if (address != NULL) { + return "The interface can't be set when using socket activation"; + } + + if (port != NULL) { + return "TCP port number can't be set when using socket activation"; + } + + return NULL; +} int main(int argc, char **argv) { @@ -471,7 +600,7 @@ int main(int argc, char **argv) off_t dev_offset = 0; uint16_t nbdflags = 0; bool disconnect = false; - const char *bindto = "0.0.0.0"; + const char *bindto = NULL; const char *port = NULL; char *sockpath = NULL; char *device = NULL; @@ -533,6 +662,7 @@ int main(int argc, char **argv) char *trace_file = NULL; bool fork_process = false; int old_stderr = -1; + unsigned socket_activation; /* The client thread uses SIGTERM to interrupt the server. A signal * handler ensures that "qemu-nbd -v -c" exits with a nice status code. @@ -751,6 +881,19 @@ int main(int argc, char **argv) trace_init_file(trace_file); qemu_set_log(LOG_TRACE); + socket_activation = check_socket_activation(); + if (socket_activation == 0) { + setup_address_and_port(&bindto, &port); + } else { + /* Using socket activation - check user didn't use -p etc. */ + const char *err_msg = socket_activation_validate_opts(device, sockpath, + bindto, port); + if (err_msg != NULL) { + error_report("%s", err_msg); + exit(EXIT_FAILURE); + } + } + if (tlscredsid) { if (sockpath) { error_report("TLS is only supported with IPv4/IPv6"); @@ -855,7 +998,25 @@ int main(int argc, char **argv) snprintf(sockpath, 128, SOCKET_PATH, basename(device)); } - saddr = nbd_build_socket_address(sockpath, bindto, port); + if (socket_activation == 0) { + server_ioc = qio_channel_socket_new(); + saddr = nbd_build_socket_address(sockpath, bindto, port); + if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) { + object_unref(OBJECT(server_ioc)); + error_report_err(local_err); + return 1; + } + } else { + /* See comment in check_socket_activation above. */ + assert(socket_activation == 1); + server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD, + &local_err); + if (server_ioc == NULL) { + error_report("Failed to use socket activation: %s", + error_get_pretty(local_err)); + exit(EXIT_FAILURE); + } + } if (qemu_init_main_loop(&local_err)) { error_report_err(local_err); @@ -950,13 +1111,6 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - server_ioc = qio_channel_socket_new(); - if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) { - object_unref(OBJECT(server_ioc)); - error_report_err(local_err); - return 1; - } - if (device) { int ret; From 3741c2503bc06c7e3c5bd46a9d4e79a11bd7e7ed Mon Sep 17 00:00:00 2001 From: Dou Liyang Date: Wed, 1 Feb 2017 10:29:38 +0800 Subject: [PATCH 18/23] vl: Move the cpu_synchronize_all_post_init() after generic devices initialization At the Qemu initialization, we call the cpu_synchronize_all_post_init() to synchronize All CPU states to KVM in the ./vl.c::main(). Currently, it is called before we initialize the CPUs, which is created by "-device" command and parsed by generic devices initialization, So, these CPUs may be ignored to synchronize. The patch moves the cpu_synchronize_all_post_init func after generic devices initialization to make sure that all the CPUs can be included. Signed-off-by: Dou Liyang Message-Id: <1485916178-17838-1-git-send-email-douly.fnst@cn.fujitsu.com> Reviewed-by: Eduardo Habkost Acked-by: Eduardo Habkost Signed-off-by: Paolo Bonzini --- vl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 0d866adce6..a05671d548 100644 --- a/vl.c +++ b/vl.c @@ -4462,8 +4462,6 @@ int main(int argc, char **argv, char **envp) audio_init(); - cpu_synchronize_all_post_init(); - if (hax_enabled()) { hax_sync_vcpus(); } @@ -4489,6 +4487,8 @@ int main(int argc, char **argv, char **envp) exit(1); } + cpu_synchronize_all_post_init(); + numa_post_machine_init(); rom_reset_order_override(); From d9e73d32a891a4d9d9b14dcdd27490ec2d13026a Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Wed, 15 Feb 2017 10:40:30 +0800 Subject: [PATCH 19/23] Makefile: avoid leaving the temporary QEMU_PKGVERSION header file By commit 67a1de0d, When we perform 'git pull && make && sudo make install', In 'make' stage a qemu-version.h.tmp will be generated. If the content of qemu-version.h.tmp and qemu-version.h aren't consistent, The qemu-version.h.tmp will be renamed to qemu-version.h. Because of the target FORCE, The same action will be do again in 'make install' stage. In 'make install' stage, If there is no qemu-version.h.tmp exists and we run 'make install' with sudo, The owner and group of new qemu-version.h.tmp will be privileged user/group. When we run 'make' next time, qemu-version.h.tmp can't be overwritten because of permission issue. This patch removed qemu-version.h.tmp after build to fix this issue. Signed-off-by: Lin Ma Message-Id: <20170215024030.23895-1-lma@suse.com> Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b993741183..830fa5a234 100644 --- a/Makefile +++ b/Makefile @@ -299,7 +299,11 @@ qemu-version.h: FORCE printf '""\n'; \ fi; \ fi) > $@.tmp) - $(call quiet-command, cmp -s $@ $@.tmp || mv $@.tmp $@) + $(call quiet-command, if ! cmp -s $@ $@.tmp; then \ + mv $@.tmp $@; \ + else \ + rm $@.tmp; \ + fi) config-host.h: config-host.h-timestamp config-host.h-timestamp: config-host.mak From d187e08dc4d0793dab1a9747b72b17a1cf0d3e43 Mon Sep 17 00:00:00 2001 From: Anton Nefedov Date: Tue, 14 Feb 2017 09:25:22 +0300 Subject: [PATCH 20/23] i386/cpu: add crash-information QOM property Windows reports BSOD parameters through Hyper-V crash MSRs. This information is very useful for initial crash analysis and thus it would be nice to have a way to fetch it. Signed-off-by: Anton Nefedov Signed-off-by: Denis V. Lunev Message-Id: <1487053524-18674-2-git-send-email-den@openvz.org> Signed-off-by: Paolo Bonzini --- kvm-all.c | 1 + qapi-schema.json | 24 +++++++++++++++++++++++ target/i386/cpu.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/kvm-all.c b/kvm-all.c index a27c880c05..64f46c8ee7 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -2000,6 +2000,7 @@ int kvm_cpu_exec(CPUState *cpu) ret = EXCP_INTERRUPT; break; case KVM_SYSTEM_EVENT_CRASH: + kvm_cpu_synchronize_state(cpu); qemu_mutex_lock_iothread(); qemu_system_guest_panicked(); qemu_mutex_unlock_iothread(); diff --git a/qapi-schema.json b/qapi-schema.json index 5edb08d621..baa0d263d6 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -5870,6 +5870,30 @@ { 'enum': 'GuestPanicAction', 'data': [ 'pause', 'poweroff' ] } +## +# @GuestPanicInformation: +# +# Information about a guest panic +# +# Since: 2.9 +## +{'union': 'GuestPanicInformation', + 'data': { 'hyper-v': 'GuestPanicInformationHyperV' } } + +## +# @GuestPanicInformationHyperV: +# +# Hyper-V specific guest panic information (HV crash MSRs) +# +# Since: 2.9 +## +{'struct': 'GuestPanicInformationHyperV', + 'data': { 'arg1': 'uint64', + 'arg2': 'uint64', + 'arg3': 'uint64', + 'arg4': 'uint64', + 'arg5': 'uint64' } } + ## # @rtc-reset-reinjection: # diff --git a/target/i386/cpu.c b/target/i386/cpu.c index eb49980ef1..71aa91fd16 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3495,6 +3495,53 @@ static void x86_cpu_register_feature_bit_props(X86CPU *cpu, x86_cpu_register_bit_prop(cpu, name, &cpu->env.features[w], bitnr); } +static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + GuestPanicInformation *panic_info = NULL; + + if (env->features[FEAT_HYPERV_EDX] & HV_X64_GUEST_CRASH_MSR_AVAILABLE) { + GuestPanicInformationHyperV *panic_info_hv = + g_malloc0(sizeof(GuestPanicInformationHyperV)); + panic_info = g_malloc0(sizeof(GuestPanicInformation)); + + panic_info->type = GUEST_PANIC_INFORMATION_KIND_HYPER_V; + panic_info->u.hyper_v.data = panic_info_hv; + + assert(HV_X64_MSR_CRASH_PARAMS >= 5); + panic_info_hv->arg1 = env->msr_hv_crash_params[0]; + panic_info_hv->arg2 = env->msr_hv_crash_params[1]; + panic_info_hv->arg3 = env->msr_hv_crash_params[2]; + panic_info_hv->arg4 = env->msr_hv_crash_params[3]; + panic_info_hv->arg5 = env->msr_hv_crash_params[4]; + } + + return panic_info; +} +static void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CPUState *cs = CPU(obj); + GuestPanicInformation *panic_info; + + if (!cs->crash_occurred) { + error_setg(errp, "No crash occured"); + return; + } + + panic_info = x86_cpu_get_crash_info(cs); + if (panic_info == NULL) { + error_setg(errp, "No crash information"); + return; + } + + visit_type_GuestPanicInformation(v, "crash-information", &panic_info, + errp); + qapi_free_GuestPanicInformation(panic_info); +} + static void x86_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); @@ -3530,6 +3577,9 @@ static void x86_cpu_initfn(Object *obj) x86_cpu_get_feature_words, NULL, NULL, (void *)cpu->filtered_features, NULL); + object_property_add(obj, "crash-information", "GuestPanicInformation", + x86_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); + cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY; for (w = 0; w < FEATURE_WORDS; w++) { From c86f106b857dd8922e29ec746a8dd47e8a15ebbd Mon Sep 17 00:00:00 2001 From: Anton Nefedov Date: Tue, 14 Feb 2017 09:25:23 +0300 Subject: [PATCH 21/23] report guest crash information in GUEST_PANICKED event it's not very convenient to use the crash-information property interface, so provide a CPU class callback to get the guest crash information, and pass that information in the event Signed-off-by: Anton Nefedov Signed-off-by: Denis V. Lunev Message-Id: <1487053524-18674-3-git-send-email-den@openvz.org> Signed-off-by: Paolo Bonzini --- hw/misc/pvpanic.c | 2 +- hw/ppc/spapr_rtas.c | 3 ++- include/qom/cpu.h | 10 ++++++++++ include/sysemu/sysemu.h | 2 +- kvm-all.c | 2 +- qapi/event.json | 6 ++++-- qom/cpu.c | 11 +++++++++++ target/i386/cpu.c | 1 + target/s390x/kvm.c | 4 ++-- vl.c | 11 ++++++++--- 10 files changed, 41 insertions(+), 11 deletions(-) diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index 0ac1e6ac9b..57da7f2199 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -42,7 +42,7 @@ static void handle_event(int event) } if (event & PVPANIC_PANICKED) { - qemu_system_guest_panicked(); + qemu_system_guest_panicked(NULL); return; } } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index bb19944686..619f32c054 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -334,7 +334,8 @@ static void rtas_ibm_os_term(PowerPCCPU *cpu, { target_ulong ret = 0; - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort); + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, false, NULL, + &error_abort); rtas_st(rets, 0, ret); } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 45bcf21a21..f69b2407ea 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -158,6 +158,7 @@ typedef struct CPUClass { uint8_t *buf, int len, bool is_write); void (*dump_state)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); + GuestPanicInformation* (*get_crash_info)(CPUState *cpu); void (*dump_statistics)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); int64_t (*get_arch_id)(CPUState *cpu); @@ -471,6 +472,15 @@ int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, void *opaque); +/** + * cpu_get_crash_info: + * @cpu: The CPU to get crash information for + * + * Gets the previously saved crash information. + * Caller is responsible for freeing the data. + */ +GuestPanicInformation *cpu_get_crash_info(CPUState *cpu); + /** * CPUDumpFlags: * @CPU_DUMP_CODE: diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index eda5241d38..576c7ce640 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -66,7 +66,7 @@ int qemu_shutdown_requested_get(void); int qemu_reset_requested_get(void); void qemu_system_killed(int signal, pid_t pid); void qemu_system_reset(bool report); -void qemu_system_guest_panicked(void); +void qemu_system_guest_panicked(GuestPanicInformation *info); size_t qemu_target_page_bits(void); void qemu_add_exit_notifier(Notifier *notify); diff --git a/kvm-all.c b/kvm-all.c index 64f46c8ee7..0c94637c46 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -2002,7 +2002,7 @@ int kvm_cpu_exec(CPUState *cpu) case KVM_SYSTEM_EVENT_CRASH: kvm_cpu_synchronize_state(cpu); qemu_mutex_lock_iothread(); - qemu_system_guest_panicked(); + qemu_system_guest_panicked(cpu_get_crash_info(cpu)); qemu_mutex_unlock_iothread(); ret = 0; break; diff --git a/qapi/event.json b/qapi/event.json index 7bf539b84d..970ff0255a 100644 --- a/qapi/event.json +++ b/qapi/event.json @@ -488,7 +488,9 @@ # # @action: action that has been taken, currently always "pause" # -# Since: 1.5 +# @info: optional information about a panic +# +# Since: 1.5 (@info since 2.9) # # Example: # @@ -497,7 +499,7 @@ # ## { 'event': 'GUEST_PANICKED', - 'data': { 'action': 'GuestPanicAction' } } + 'data': { 'action': 'GuestPanicAction', '*info': 'GuestPanicInformation' } } ## # @QUORUM_FAILURE: diff --git a/qom/cpu.c b/qom/cpu.c index 0e19b1aa21..ed87c50cea 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -218,6 +218,17 @@ static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req) return false; } +GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + GuestPanicInformation *res = NULL; + + if (cc->get_crash_info) { + res = cc->get_crash_info(cpu); + } + return res; +} + void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags) { diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 71aa91fd16..fd7add2521 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3734,6 +3734,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->do_interrupt = x86_cpu_do_interrupt; cc->cpu_exec_interrupt = x86_cpu_exec_interrupt; cc->dump_state = x86_cpu_dump_state; + cc->get_crash_info = x86_cpu_get_crash_info; cc->set_pc = x86_cpu_set_pc; cc->synchronize_from_tb = x86_cpu_synchronize_from_tb; cc->gdb_read_register = x86_cpu_gdb_read_register; diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 6ed387671e..25367807f4 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -1864,7 +1864,7 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset), ldq_phys(cs->as, cpu->env.psa + pswoffset + 8)); s390_cpu_halt(cpu); - qemu_system_guest_panicked(); + qemu_system_guest_panicked(NULL); } static int handle_intercept(S390CPU *cpu) @@ -1897,7 +1897,7 @@ static int handle_intercept(S390CPU *cpu) if (is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } else { - qemu_system_guest_panicked(); + qemu_system_guest_panicked(NULL); } } r = EXCP_HALTED; diff --git a/vl.c b/vl.c index a05671d548..5993270185 100644 --- a/vl.c +++ b/vl.c @@ -1679,18 +1679,23 @@ void qemu_system_reset(bool report) cpu_synchronize_all_post_reset(); } -void qemu_system_guest_panicked(void) +void qemu_system_guest_panicked(GuestPanicInformation *info) { if (current_cpu) { current_cpu->crash_occurred = true; } - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort); + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, + !!info, info, &error_abort); vm_stop(RUN_STATE_GUEST_PANICKED); if (!no_shutdown) { qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_POWEROFF, - &error_abort); + !!info, info, &error_abort); qemu_system_shutdown_request(); } + + if (info) { + qapi_free_GuestPanicInformation(info); + } } void qemu_system_reset_request(void) From f47291b7a7ffa8854300283d4773ed17d5d581c1 Mon Sep 17 00:00:00 2001 From: Anton Nefedov Date: Tue, 14 Feb 2017 09:25:24 +0300 Subject: [PATCH 22/23] vl: log available guest crash information There is a suitable log mask for the purpose. Signed-off-by: Anton Nefedov Signed-off-by: Denis V. Lunev Message-Id: <1487053524-18674-4-git-send-email-den@openvz.org> Signed-off-by: Paolo Bonzini --- vl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vl.c b/vl.c index 5993270185..27d982981a 100644 --- a/vl.c +++ b/vl.c @@ -1681,6 +1681,8 @@ void qemu_system_reset(bool report) void qemu_system_guest_panicked(GuestPanicInformation *info) { + qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed\n"); + if (current_cpu) { current_cpu->crash_occurred = true; } @@ -1694,6 +1696,15 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) } if (info) { + if (info->type == GUEST_PANIC_INFORMATION_KIND_HYPER_V) { + qemu_log_mask(LOG_GUEST_ERROR, "HV crash parameters: (%#"PRIx64 + " %#"PRIx64" %#"PRIx64" %#"PRIx64" %#"PRIx64")\n", + info->u.hyper_v.data->arg1, + info->u.hyper_v.data->arg2, + info->u.hyper_v.data->arg3, + info->u.hyper_v.data->arg4, + info->u.hyper_v.data->arg5); + } qapi_free_GuestPanicInformation(info); } } From 65c9d60a3ad3249784348824eca69acac455bc02 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 16 Feb 2017 12:30:05 +0100 Subject: [PATCH 23/23] target-i386: correctly propagate retaddr into SVM helpers Commit 2afbdf8 ("target-i386: exception handling for memory helpers", 2015-09-15) changed tlb_fill's cpu_restore_state+raise_exception_err to raise_exception_err_ra. After this change, the cpu_restore_state and raise_exception_err's cpu_loop_exit are merged into raise_exception_err_ra's cpu_loop_exit_restore. This actually fixed some bugs, but when SVM is enabled there is a second path from raise_exception_err_ra to cpu_loop_exit. This is the VMEXIT path, and now cpu_vmexit is called without a cpu_restore_state before. The fix is to pass the retaddr to cpu_vmexit (via cpu_svm_check_intercept_param). All helpers can now use GETPC() to pass the correct retaddr, too. Cc: qemu-stable@nongnu.org Fixes: 2afbdf84807d673eb682cb78158e11cdacbf4673 Reported-by: Alexander Boettcher Tested-by: Alexander Boettcher Signed-off-by: Paolo Bonzini --- cpu-exec.c | 2 +- target/i386/cpu.h | 5 +-- target/i386/excp_helper.c | 11 ++++--- target/i386/helper.h | 1 - target/i386/misc_helper.c | 24 +++++++-------- target/i386/seg_helper.c | 6 ++-- target/i386/svm_helper.c | 65 +++++++++++++++++++-------------------- 7 files changed, 56 insertions(+), 58 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index b8ebb5ccd6..142a5862fc 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -491,7 +491,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, X86CPU *x86_cpu = X86_CPU(cpu); CPUArchState *env = &x86_cpu->env; replay_interrupt(); - cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0, 0); do_cpu_init(x86_cpu); cpu->exception_index = EXCP_HALTED; return true; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 4d788d56fc..8df124f332 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1621,8 +1621,9 @@ void helper_lock_init(void); /* svm_helper.c */ void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type, - uint64_t param); -void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1); + uint64_t param, uintptr_t retaddr); +void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, + uintptr_t retaddr); /* seg_helper.c */ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); diff --git a/target/i386/excp_helper.c b/target/i386/excp_helper.c index f0dc4996c1..ee596c6082 100644 --- a/target/i386/excp_helper.c +++ b/target/i386/excp_helper.c @@ -39,7 +39,8 @@ void helper_raise_exception(CPUX86State *env, int exception_index) * needed. It should only be called, if this is not an interrupt. * Returns the new exception number. */ -static int check_exception(CPUX86State *env, int intno, int *error_code) +static int check_exception(CPUX86State *env, int intno, int *error_code, + uintptr_t retaddr) { int first_contributory = env->old_exception == 0 || (env->old_exception >= 10 && @@ -53,7 +54,7 @@ static int check_exception(CPUX86State *env, int intno, int *error_code) #if !defined(CONFIG_USER_ONLY) if (env->old_exception == EXCP08_DBLE) { if (env->hflags & HF_SVMI_MASK) { - cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0); /* does not return */ + cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0, retaddr); /* does not return */ } qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); @@ -93,10 +94,10 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, if (!is_int) { cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno, - error_code); - intno = check_exception(env, intno, &error_code); + error_code, retaddr); + intno = check_exception(env, intno, &error_code, retaddr); } else { - cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, retaddr); } cs->exception_index = intno; diff --git a/target/i386/helper.h b/target/i386/helper.h index 4c1aafffd6..6fb8fb9b74 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -99,7 +99,6 @@ DEF_HELPER_2(inl, tl, env, i32) DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl) DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64) -DEF_HELPER_3(vmexit, void, env, i32, i64) DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32) DEF_HELPER_3(vmrun, void, env, int, int) DEF_HELPER_1(vmmcall, void, env) diff --git a/target/i386/misc_helper.c b/target/i386/misc_helper.c index 5029efef47..ca2ea09f54 100644 --- a/target/i386/misc_helper.c +++ b/target/i386/misc_helper.c @@ -101,7 +101,7 @@ void helper_cpuid(CPUX86State *env) { uint32_t eax, ebx, ecx, edx; - cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC()); cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX], &eax, &ebx, &ecx, &edx); @@ -125,7 +125,7 @@ target_ulong helper_read_crN(CPUX86State *env, int reg) { target_ulong val; - cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC()); switch (reg) { default: val = env->cr[reg]; @@ -143,7 +143,7 @@ target_ulong helper_read_crN(CPUX86State *env, int reg) void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) { - cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC()); switch (reg) { case 0: cpu_x86_update_cr0(env, t0); @@ -179,7 +179,7 @@ void helper_invlpg(CPUX86State *env, target_ulong addr) { X86CPU *cpu = x86_env_get_cpu(env); - cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC()); tlb_flush_page(CPU(cpu), addr); } @@ -190,7 +190,7 @@ void helper_rdtsc(CPUX86State *env) if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { raise_exception_ra(env, EXCP0D_GPF, GETPC()); } - cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC()); val = cpu_get_tsc(env) + env->tsc_offset; env->regs[R_EAX] = (uint32_t)(val); @@ -208,7 +208,7 @@ void helper_rdpmc(CPUX86State *env) if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { raise_exception_ra(env, EXCP0D_GPF, GETPC()); } - cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC()); /* currently unimplemented */ qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n"); @@ -228,7 +228,7 @@ void helper_wrmsr(CPUX86State *env) { uint64_t val; - cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1); + cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC()); val = ((uint32_t)env->regs[R_EAX]) | ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32); @@ -388,7 +388,7 @@ void helper_rdmsr(CPUX86State *env) { uint64_t val; - cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC()); switch ((uint32_t)env->regs[R_ECX]) { case MSR_IA32_SYSENTER_CS: @@ -557,7 +557,7 @@ void helper_hlt(CPUX86State *env, int next_eip_addend) { X86CPU *cpu = x86_env_get_cpu(env); - cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC()); env->eip += next_eip_addend; do_hlt(cpu); @@ -569,7 +569,7 @@ void helper_monitor(CPUX86State *env, target_ulong ptr) raise_exception_ra(env, EXCP0D_GPF, GETPC()); } /* XXX: store address? */ - cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC()); } void helper_mwait(CPUX86State *env, int next_eip_addend) @@ -580,7 +580,7 @@ void helper_mwait(CPUX86State *env, int next_eip_addend) if ((uint32_t)env->regs[R_ECX] != 0) { raise_exception_ra(env, EXCP0D_GPF, GETPC()); } - cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC()); env->eip += next_eip_addend; cpu = x86_env_get_cpu(env); @@ -597,7 +597,7 @@ void helper_pause(CPUX86State *env, int next_eip_addend) { X86CPU *cpu = x86_env_get_cpu(env); - cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC()); env->eip += next_eip_addend; do_pause(cpu); diff --git a/target/i386/seg_helper.c b/target/i386/seg_helper.c index d24574da7f..5c845dc25c 100644 --- a/target/i386/seg_helper.c +++ b/target/i386/seg_helper.c @@ -1335,7 +1335,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } else if (env->hflags2 & HF2_GIF_MASK) { if ((interrupt_request & CPU_INTERRUPT_SMI) && !(env->hflags & HF_SMM_MASK)) { - cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0); cs->interrupt_request &= ~CPU_INTERRUPT_SMI; do_smm_enter(cpu); ret = true; @@ -1356,7 +1356,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) (env->eflags & IF_MASK && !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { int intno; - cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0, 0); cs->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); intno = cpu_get_pic_interrupt(env); @@ -1372,7 +1372,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; /* FIXME: this should respect TPR */ - cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0, 0); intno = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); qemu_log_mask(CPU_LOG_TB_IN_ASM, diff --git a/target/i386/svm_helper.c b/target/i386/svm_helper.c index 210f6aa7b5..78d8df4af6 100644 --- a/target/i386/svm_helper.c +++ b/target/i386/svm_helper.c @@ -60,11 +60,8 @@ void helper_invlpga(CPUX86State *env, int aflag) { } -void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) -{ -} - -void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1) +void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, + uintptr_t retaddr) { } @@ -74,7 +71,7 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, } void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param) + uint64_t param, uintptr_t retaddr) { } @@ -130,7 +127,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) uint32_t event_inj; uint32_t int_ctl; - cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); if (aflag == 2) { addr = env->regs[R_EAX]; @@ -355,7 +352,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) void helper_vmmcall(CPUX86State *env) { - cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0, GETPC()); raise_exception(env, EXCP06_ILLOP); } @@ -364,7 +361,7 @@ void helper_vmload(CPUX86State *env, int aflag) CPUState *cs = CPU(x86_env_get_cpu(env)); target_ulong addr; - cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); if (aflag == 2) { addr = env->regs[R_EAX]; @@ -404,7 +401,7 @@ void helper_vmsave(CPUX86State *env, int aflag) CPUState *cs = CPU(x86_env_get_cpu(env)); target_ulong addr; - cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); if (aflag == 2) { addr = env->regs[R_EAX]; @@ -445,19 +442,19 @@ void helper_vmsave(CPUX86State *env, int aflag) void helper_stgi(CPUX86State *env) { - cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC()); env->hflags2 |= HF2_GIF_MASK; } void helper_clgi(CPUX86State *env) { - cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC()); env->hflags2 &= ~HF2_GIF_MASK; } void helper_skinit(CPUX86State *env) { - cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0, GETPC()); /* XXX: not implemented */ raise_exception(env, EXCP06_ILLOP); } @@ -467,7 +464,7 @@ void helper_invlpga(CPUX86State *env, int aflag) X86CPU *cpu = x86_env_get_cpu(env); target_ulong addr; - cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0); + cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0, GETPC()); if (aflag == 2) { addr = env->regs[R_EAX]; @@ -480,8 +477,8 @@ void helper_invlpga(CPUX86State *env, int aflag) tlb_flush_page(CPU(cpu), addr); } -void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param) +void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, + uint64_t param, uintptr_t retaddr) { CPUState *cs = CPU(x86_env_get_cpu(env)); @@ -491,27 +488,27 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, switch (type) { case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) { - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); } break; case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) { - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); } break; case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7: if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) { - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); } break; case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7: if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) { - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); } break; case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31: if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) { - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); } break; case SVM_EXIT_MSR: @@ -538,28 +535,28 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, t0 %= 8; break; default: - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); t0 = 0; t1 = 0; break; } if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) { - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); } } break; default: if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) { - helper_vmexit(env, type, param); + cpu_vmexit(env, type, param, retaddr); } break; } } -void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param) +void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, + uint64_t param) { - helper_svm_check_intercept_param(env, type, param); + cpu_svm_check_intercept_param(env, type, param, GETPC()); } void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, @@ -578,17 +575,22 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), env->eip + next_eip_addend); - helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16)); + cpu_vmexit(env, SVM_EXIT_IOIO, param | (port << 16), GETPC()); } } } /* Note: currently only 32 bits of exit_code are used */ -void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) +void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, + uintptr_t retaddr) { CPUState *cs = CPU(x86_env_get_cpu(env)); uint32_t int_ctl; + if (retaddr) { + cpu_restore_state(cs, retaddr); + } + qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", exit_code, exit_info_1, @@ -766,9 +768,4 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) cpu_loop_exit(cs); } -void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) -{ - helper_vmexit(env, exit_code, exit_info_1); -} - #endif