2010-03-29 23:23:50 +04:00
|
|
|
/*
|
|
|
|
* QEMU System Emulator
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2016-01-26 21:16:56 +03:00
|
|
|
#include "qemu/osdep.h"
|
2019-05-23 17:35:08 +03:00
|
|
|
#include "qemu-common.h"
|
2012-12-17 21:19:49 +04:00
|
|
|
#include "monitor/monitor.h"
|
2018-02-01 14:18:31 +03:00
|
|
|
#include "qapi/error.h"
|
2020-10-12 15:15:32 +03:00
|
|
|
#include "qapi/qapi-commands-machine.h"
|
2018-02-27 02:13:27 +03:00
|
|
|
#include "qapi/qapi-commands-misc.h"
|
2018-02-11 12:36:01 +03:00
|
|
|
#include "qapi/qapi-events-run-state.h"
|
2014-06-18 10:43:36 +04:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2012-12-17 21:19:49 +04:00
|
|
|
#include "exec/gdbstub.h"
|
2017-01-10 13:59:55 +03:00
|
|
|
#include "sysemu/hw_accel.h"
|
2016-03-15 15:18:37 +03:00
|
|
|
#include "exec/exec-all.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/thread.h"
|
2018-10-21 20:30:35 +03:00
|
|
|
#include "qemu/plugin.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/cpus.h"
|
2019-03-14 23:06:29 +03:00
|
|
|
#include "qemu/guest-random.h"
|
2014-08-20 16:16:33 +04:00
|
|
|
#include "hw/nmi.h"
|
2015-09-17 19:24:05 +03:00
|
|
|
#include "sysemu/replay.h"
|
2019-08-12 08:23:59 +03:00
|
|
|
#include "sysemu/runstate.h"
|
2020-08-19 14:17:19 +03:00
|
|
|
#include "sysemu/cpu-timers.h"
|
2020-10-28 05:23:19 +03:00
|
|
|
#include "sysemu/whpx.h"
|
2019-05-18 23:54:21 +03:00
|
|
|
#include "hw/boards.h"
|
2019-08-12 08:23:48 +03:00
|
|
|
#include "hw/hw.h"
|
2021-04-15 16:33:51 +03:00
|
|
|
#include "trace.h"
|
2011-06-23 12:15:55 +04:00
|
|
|
|
2011-02-02 00:15:58 +03:00
|
|
|
#ifdef CONFIG_LINUX
|
|
|
|
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
|
2010-10-11 22:31:21 +04:00
|
|
|
#ifndef PR_MCE_KILL
|
|
|
|
#define PR_MCE_KILL 33
|
|
|
|
#endif
|
|
|
|
|
2011-02-02 00:15:58 +03:00
|
|
|
#ifndef PR_MCE_KILL_SET
|
|
|
|
#define PR_MCE_KILL_SET 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PR_MCE_KILL_EARLY
|
|
|
|
#define PR_MCE_KILL_EARLY 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* CONFIG_LINUX */
|
|
|
|
|
2019-09-09 16:13:34 +03:00
|
|
|
static QemuMutex qemu_global_mutex;
|
|
|
|
|
2013-08-02 05:43:09 +04:00
|
|
|
bool cpu_is_stopped(CPUState *cpu)
|
|
|
|
{
|
|
|
|
return cpu->stopped || !runstate_is_running();
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
bool cpu_work_list_empty(CPUState *cpu)
|
2020-06-12 22:02:24 +03:00
|
|
|
{
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
qemu_mutex_lock(&cpu->work_mutex);
|
|
|
|
ret = QSIMPLEQ_EMPTY(&cpu->work_list);
|
|
|
|
qemu_mutex_unlock(&cpu->work_mutex);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
bool cpu_thread_is_idle(CPUState *cpu)
|
2012-07-19 19:52:27 +04:00
|
|
|
{
|
2020-06-12 22:02:24 +03:00
|
|
|
if (cpu->stop || !cpu_work_list_empty(cpu)) {
|
2012-07-19 19:52:27 +04:00
|
|
|
return false;
|
|
|
|
}
|
2013-08-02 05:43:09 +04:00
|
|
|
if (cpu_is_stopped(cpu)) {
|
2012-07-19 19:52:27 +04:00
|
|
|
return true;
|
|
|
|
}
|
2013-08-25 20:53:55 +04:00
|
|
|
if (!cpu->halted || cpu_has_work(cpu) ||
|
2020-10-28 05:23:19 +03:00
|
|
|
kvm_halt_in_kernel() || whpx_apic_in_platform()) {
|
2012-07-19 19:52:27 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-19 14:17:19 +03:00
|
|
|
bool all_cpu_threads_idle(void)
|
2012-07-19 19:52:27 +04:00
|
|
|
{
|
2013-05-30 00:29:20 +04:00
|
|
|
CPUState *cpu;
|
2012-07-19 19:52:27 +04:00
|
|
|
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2013-05-30 00:29:20 +04:00
|
|
|
if (!cpu_thread_is_idle(cpu)) {
|
2012-07-19 19:52:27 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-03-29 23:23:50 +04:00
|
|
|
/***********************************************************/
|
|
|
|
void hw_error(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
2012-12-17 09:18:02 +04:00
|
|
|
CPUState *cpu;
|
2010-03-29 23:23:50 +04:00
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
fprintf(stderr, "qemu: hardware error: ");
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
|
|
fprintf(stderr, "\n");
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2012-12-17 09:18:02 +04:00
|
|
|
fprintf(stderr, "CPU #%d:\n", cpu->cpu_index);
|
2019-04-17 22:18:02 +03:00
|
|
|
cpu_dump_state(cpu, stderr, CPU_DUMP_FPU);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
/*
|
|
|
|
* The chosen accelerator is supposed to register this.
|
|
|
|
*/
|
2021-02-04 19:39:25 +03:00
|
|
|
static const AccelOpsClass *cpus_accel;
|
2020-07-31 13:23:42 +03:00
|
|
|
|
2010-03-29 23:23:50 +04:00
|
|
|
void cpu_synchronize_all_states(void)
|
|
|
|
{
|
2013-05-30 00:29:20 +04:00
|
|
|
CPUState *cpu;
|
2010-03-29 23:23:50 +04:00
|
|
|
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2013-05-30 00:29:20 +04:00
|
|
|
cpu_synchronize_state(cpu);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cpu_synchronize_all_post_reset(void)
|
|
|
|
{
|
2013-05-30 00:29:20 +04:00
|
|
|
CPUState *cpu;
|
2010-03-29 23:23:50 +04:00
|
|
|
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2013-05-30 00:29:20 +04:00
|
|
|
cpu_synchronize_post_reset(cpu);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cpu_synchronize_all_post_init(void)
|
|
|
|
{
|
2013-05-30 00:29:20 +04:00
|
|
|
CPUState *cpu;
|
2010-03-29 23:23:50 +04:00
|
|
|
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2013-05-30 00:29:20 +04:00
|
|
|
cpu_synchronize_post_init(cpu);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-26 07:46:28 +03:00
|
|
|
void cpu_synchronize_all_pre_loadvm(void)
|
|
|
|
{
|
|
|
|
CPUState *cpu;
|
|
|
|
|
|
|
|
CPU_FOREACH(cpu) {
|
|
|
|
cpu_synchronize_pre_loadvm(cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
void cpu_synchronize_state(CPUState *cpu)
|
|
|
|
{
|
2020-08-19 17:01:03 +03:00
|
|
|
if (cpus_accel->synchronize_state) {
|
2020-07-31 13:23:42 +03:00
|
|
|
cpus_accel->synchronize_state(cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cpu_synchronize_post_reset(CPUState *cpu)
|
|
|
|
{
|
2020-08-19 17:01:03 +03:00
|
|
|
if (cpus_accel->synchronize_post_reset) {
|
2020-07-31 13:23:42 +03:00
|
|
|
cpus_accel->synchronize_post_reset(cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cpu_synchronize_post_init(CPUState *cpu)
|
|
|
|
{
|
2020-08-19 17:01:03 +03:00
|
|
|
if (cpus_accel->synchronize_post_init) {
|
2020-07-31 13:23:42 +03:00
|
|
|
cpus_accel->synchronize_post_init(cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cpu_synchronize_pre_loadvm(CPUState *cpu)
|
|
|
|
{
|
2020-08-19 17:01:03 +03:00
|
|
|
if (cpus_accel->synchronize_pre_loadvm) {
|
2020-07-31 13:23:42 +03:00
|
|
|
cpus_accel->synchronize_pre_loadvm(cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-26 20:36:47 +03:00
|
|
|
bool cpus_are_resettable(void)
|
|
|
|
{
|
|
|
|
return cpu_check_are_resettable();
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
int64_t cpus_get_virtual_clock(void)
|
|
|
|
{
|
2020-08-19 17:01:03 +03:00
|
|
|
/*
|
|
|
|
* XXX
|
|
|
|
*
|
|
|
|
* need to check that cpus_accel is not NULL, because qcow2 calls
|
|
|
|
* qemu_get_clock_ns(CLOCK_VIRTUAL) without any accel initialized and
|
|
|
|
* with ticks disabled in some io-tests:
|
|
|
|
* 030 040 041 060 099 120 127 140 156 161 172 181 191 192 195 203 229 249 256 267
|
|
|
|
*
|
|
|
|
* is this expected?
|
|
|
|
*
|
|
|
|
* XXX
|
|
|
|
*/
|
2020-07-31 13:23:42 +03:00
|
|
|
if (cpus_accel && cpus_accel->get_virtual_clock) {
|
|
|
|
return cpus_accel->get_virtual_clock();
|
|
|
|
}
|
|
|
|
return cpu_get_clock();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return the time elapsed in VM between vm_start and vm_stop. Unless
|
|
|
|
* icount is active, cpus_get_elapsed_ticks() uses units of the host CPU cycle
|
|
|
|
* counter.
|
|
|
|
*/
|
|
|
|
int64_t cpus_get_elapsed_ticks(void)
|
|
|
|
{
|
2020-08-19 17:01:03 +03:00
|
|
|
if (cpus_accel->get_elapsed_ticks) {
|
2020-07-31 13:23:42 +03:00
|
|
|
return cpus_accel->get_elapsed_ticks();
|
|
|
|
}
|
|
|
|
return cpu_get_ticks();
|
|
|
|
}
|
|
|
|
|
2020-08-11 16:16:33 +03:00
|
|
|
static void generic_handle_interrupt(CPUState *cpu, int mask)
|
|
|
|
{
|
|
|
|
cpu->interrupt_request |= mask;
|
|
|
|
|
|
|
|
if (!qemu_cpu_is_self(cpu)) {
|
|
|
|
qemu_cpu_kick(cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cpu_interrupt(CPUState *cpu, int mask)
|
|
|
|
{
|
|
|
|
if (cpus_accel->handle_interrupt) {
|
|
|
|
cpus_accel->handle_interrupt(cpu, mask);
|
|
|
|
} else {
|
|
|
|
generic_handle_interrupt(cpu, mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 17:42:05 +03:00
|
|
|
static int do_vm_stop(RunState state, bool send_stop)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2013-07-05 15:49:54 +04:00
|
|
|
int ret = 0;
|
|
|
|
|
2011-07-29 22:36:43 +04:00
|
|
|
if (runstate_is_running()) {
|
2020-03-16 11:37:32 +03:00
|
|
|
runstate_set(state);
|
2010-03-29 23:23:50 +04:00
|
|
|
cpu_disable_ticks();
|
|
|
|
pause_all_vcpus();
|
2011-07-29 21:26:33 +04:00
|
|
|
vm_state_notify(0, state);
|
2018-03-07 17:42:05 +03:00
|
|
|
if (send_stop) {
|
2018-08-15 16:37:37 +03:00
|
|
|
qapi_event_send_stop();
|
2018-03-07 17:42:05 +03:00
|
|
|
}
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
2013-07-05 15:49:54 +04:00
|
|
|
|
2013-07-18 16:52:19 +04:00
|
|
|
bdrv_drain_all();
|
2016-09-23 04:45:51 +03:00
|
|
|
ret = bdrv_flush_all();
|
2021-04-15 16:33:51 +03:00
|
|
|
trace_vm_stop_flush_all(ret);
|
2013-07-18 16:52:19 +04:00
|
|
|
|
2013-07-05 15:49:54 +04:00
|
|
|
return ret;
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2018-03-07 17:42:05 +03:00
|
|
|
/* Special vm_stop() variant for terminating the process. Historically clients
|
|
|
|
* did not expect a QMP STOP event and so we need to retain compatibility.
|
|
|
|
*/
|
|
|
|
int vm_shutdown(void)
|
|
|
|
{
|
|
|
|
return do_vm_stop(RUN_STATE_SHUTDOWN, false);
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
bool cpu_can_run(CPUState *cpu)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2012-05-03 01:10:09 +04:00
|
|
|
if (cpu->stop) {
|
2012-05-03 01:42:26 +04:00
|
|
|
return false;
|
2011-02-07 14:19:14 +03:00
|
|
|
}
|
2013-08-02 05:43:09 +04:00
|
|
|
if (cpu_is_stopped(cpu)) {
|
2012-05-03 01:42:26 +04:00
|
|
|
return false;
|
2011-02-07 14:19:14 +03:00
|
|
|
}
|
2012-05-03 01:42:26 +04:00
|
|
|
return true;
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
void cpu_handle_guest_debug(CPUState *cpu)
|
2011-02-07 14:19:17 +03:00
|
|
|
{
|
2020-10-03 20:13:43 +03:00
|
|
|
if (replay_running_debug()) {
|
|
|
|
if (!cpu->singlestep_enabled) {
|
2020-10-03 20:13:49 +03:00
|
|
|
/*
|
|
|
|
* Report about the breakpoint and
|
|
|
|
* make a single step to skip it
|
|
|
|
*/
|
|
|
|
replay_breakpoint();
|
2020-10-03 20:13:43 +03:00
|
|
|
cpu_single_step(cpu, SSTEP_ENABLE);
|
|
|
|
} else {
|
|
|
|
cpu_single_step(cpu, 0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
gdb_set_stop_cpu(cpu);
|
|
|
|
qemu_system_debug_request();
|
|
|
|
cpu->stopped = true;
|
|
|
|
}
|
2010-06-25 18:56:56 +04:00
|
|
|
}
|
|
|
|
|
2011-02-02 00:15:58 +03:00
|
|
|
#ifdef CONFIG_LINUX
|
|
|
|
static void sigbus_reraise(void)
|
|
|
|
{
|
|
|
|
sigset_t set;
|
|
|
|
struct sigaction action;
|
|
|
|
|
|
|
|
memset(&action, 0, sizeof(action));
|
|
|
|
action.sa_handler = SIG_DFL;
|
|
|
|
if (!sigaction(SIGBUS, &action, NULL)) {
|
|
|
|
raise(SIGBUS);
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SIGBUS);
|
2016-05-16 20:33:59 +03:00
|
|
|
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
2011-02-02 00:15:58 +03:00
|
|
|
}
|
2021-07-06 12:44:33 +03:00
|
|
|
perror("Failed to re-raise SIGBUS!");
|
2011-02-02 00:15:58 +03:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2017-02-08 15:22:12 +03:00
|
|
|
static void sigbus_handler(int n, siginfo_t *siginfo, void *ctx)
|
2011-02-02 00:15:58 +03:00
|
|
|
{
|
2017-02-09 11:50:02 +03:00
|
|
|
if (siginfo->si_code != BUS_MCEERR_AO && siginfo->si_code != BUS_MCEERR_AR) {
|
|
|
|
sigbus_reraise();
|
|
|
|
}
|
|
|
|
|
2017-02-08 14:48:54 +03:00
|
|
|
if (current_cpu) {
|
|
|
|
/* Called asynchronously in VCPU thread. */
|
|
|
|
if (kvm_on_sigbus_vcpu(current_cpu, siginfo->si_code, siginfo->si_addr)) {
|
|
|
|
sigbus_reraise();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Called synchronously (via signalfd) in main thread. */
|
|
|
|
if (kvm_on_sigbus(siginfo->si_code, siginfo->si_addr)) {
|
|
|
|
sigbus_reraise();
|
|
|
|
}
|
2011-02-02 00:15:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qemu_init_sigbus(void)
|
|
|
|
{
|
|
|
|
struct sigaction action;
|
|
|
|
|
|
|
|
memset(&action, 0, sizeof(action));
|
|
|
|
action.sa_flags = SA_SIGINFO;
|
2017-02-08 15:22:12 +03:00
|
|
|
action.sa_sigaction = sigbus_handler;
|
2011-02-02 00:15:58 +03:00
|
|
|
sigaction(SIGBUS, &action, NULL);
|
|
|
|
|
|
|
|
prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
|
|
|
|
}
|
|
|
|
#else /* !CONFIG_LINUX */
|
|
|
|
static void qemu_init_sigbus(void)
|
|
|
|
{
|
|
|
|
}
|
2017-02-09 11:50:02 +03:00
|
|
|
#endif /* !CONFIG_LINUX */
|
2011-02-02 00:15:53 +03:00
|
|
|
|
2010-03-29 23:23:50 +04:00
|
|
|
static QemuThread io_thread;
|
|
|
|
|
|
|
|
/* cpu creation */
|
|
|
|
static QemuCond qemu_cpu_cond;
|
|
|
|
/* system init */
|
|
|
|
static QemuCond qemu_pause_cond;
|
|
|
|
|
2011-09-13 12:30:52 +04:00
|
|
|
void qemu_init_cpu_loop(void)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2011-02-02 00:15:58 +03:00
|
|
|
qemu_init_sigbus();
|
2011-02-08 20:18:18 +03:00
|
|
|
qemu_cond_init(&qemu_cpu_cond);
|
|
|
|
qemu_cond_init(&qemu_pause_cond);
|
2010-03-29 23:23:50 +04:00
|
|
|
qemu_mutex_init(&qemu_global_mutex);
|
|
|
|
|
2011-03-12 19:43:51 +03:00
|
|
|
qemu_thread_get_self(&io_thread);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2016-10-31 12:36:08 +03:00
|
|
|
void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
|
2010-05-04 16:45:22 +04:00
|
|
|
{
|
2016-08-29 10:51:00 +03:00
|
|
|
do_run_on_cpu(cpu, func, data, &qemu_global_mutex);
|
2013-06-24 13:49:41 +04:00
|
|
|
}
|
|
|
|
|
2017-11-29 22:12:15 +03:00
|
|
|
static void qemu_cpu_stop(CPUState *cpu, bool exit)
|
|
|
|
{
|
|
|
|
g_assert(qemu_cpu_is_self(cpu));
|
|
|
|
cpu->stop = false;
|
|
|
|
cpu->stopped = true;
|
|
|
|
if (exit) {
|
|
|
|
cpu_exit(cpu);
|
|
|
|
}
|
|
|
|
qemu_cond_broadcast(&qemu_pause_cond);
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
void qemu_wait_io_event_common(CPUState *cpu)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2020-09-23 13:56:46 +03:00
|
|
|
qatomic_mb_set(&cpu->thread_kicked, false);
|
2012-05-03 01:10:09 +04:00
|
|
|
if (cpu->stop) {
|
2017-11-29 22:12:15 +03:00
|
|
|
qemu_cpu_stop(cpu, false);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
2016-08-02 20:27:36 +03:00
|
|
|
process_queued_cpu_work(cpu);
|
2017-02-23 21:29:14 +03:00
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
void qemu_wait_io_event(CPUState *cpu)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2018-10-21 20:30:35 +03:00
|
|
|
bool slept = false;
|
|
|
|
|
2013-05-27 01:21:08 +04:00
|
|
|
while (cpu_thread_is_idle(cpu)) {
|
2018-10-21 20:30:35 +03:00
|
|
|
if (!slept) {
|
|
|
|
slept = true;
|
|
|
|
qemu_plugin_vcpu_idle_cb(cpu);
|
|
|
|
}
|
2012-05-03 03:22:49 +04:00
|
|
|
qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
|
2011-02-09 18:29:37 +03:00
|
|
|
}
|
2018-10-21 20:30:35 +03:00
|
|
|
if (slept) {
|
|
|
|
qemu_plugin_vcpu_resume_cb(cpu);
|
|
|
|
}
|
2010-03-29 23:23:50 +04:00
|
|
|
|
2018-01-11 15:53:12 +03:00
|
|
|
#ifdef _WIN32
|
2020-07-31 13:23:42 +03:00
|
|
|
/* Eat dummy APC queued by cpus_kick_thread. */
|
|
|
|
if (hax_enabled()) {
|
2018-01-11 15:53:12 +03:00
|
|
|
SleepEx(0, TRUE);
|
i386: hvf: add code base from Google's QEMU repository
This file begins tracking the files that will be the code base for HVF
support in QEMU. This code base is part of Google's QEMU version of
their Android emulator, and can be found at
https://android.googlesource.com/platform/external/qemu/+/emu-master-dev
This code is based on Veertu Inc's vdhh (Veertu Desktop Hosted
Hypervisor), found at https://github.com/veertuinc/vdhh. Everything is
appropriately licensed under GPL v2-or-later, except for the code inside
x86_task.c and x86_task.h, which, deriving from KVM (the Linux kernel),
is licensed GPL v2-only.
This code base already implements a very great deal of functionality,
although Google's version removed from Vertuu's the support for APIC
page and hyperv-related stuff. According to the Android Emulator Release
Notes, Revision 26.1.3 (August 2017), "Hypervisor.framework is now
enabled by default on macOS for 32-bit x86 images to improve performance
and macOS compatibility", although we better use with caution for, as the
same Revision warns us, "If you experience issues with it specifically,
please file a bug report...". The code hasn't seen much update in the
last 5 months, so I think that we can further develop the code with
occasional visiting Google's repository to see if there has been any
update.
On top of Google's code, the following changes were made:
- add code to the configure script to support the --enable-hvf argument.
If the OS is Darwin, it checks for presence of HVF in the system. The
patch also adds strings related to HVF in the file qemu-options.hx.
QEMU will only support the modern syntax style '-M accel=hvf' no enable
hvf; the legacy '-enable-hvf' will not be supported.
- fix styling issues
- add glue code to cpus.c
- move HVFX86EmulatorState field to CPUX86State, changing the
the emulation functions to have a parameter with signature 'CPUX86State *'
instead of 'CPUState *' so we don't have to get the 'env'.
Signed-off-by: Sergio Andres Gomez Del Real <Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-2-Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-3-Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-5-Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-6-Sergio.G.DelReal@gmail.com>
Message-Id: <20170905035457.3753-7-Sergio.G.DelReal@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-09-13 12:05:09 +03:00
|
|
|
}
|
2018-01-11 15:53:12 +03:00
|
|
|
#endif
|
i386: hvf: add code base from Google's QEMU repository
This file begins tracking the files that will be the code base for HVF
support in QEMU. This code base is part of Google's QEMU version of
their Android emulator, and can be found at
https://android.googlesource.com/platform/external/qemu/+/emu-master-dev
This code is based on Veertu Inc's vdhh (Veertu Desktop Hosted
Hypervisor), found at https://github.com/veertuinc/vdhh. Everything is
appropriately licensed under GPL v2-or-later, except for the code inside
x86_task.c and x86_task.h, which, deriving from KVM (the Linux kernel),
is licensed GPL v2-only.
This code base already implements a very great deal of functionality,
although Google's version removed from Vertuu's the support for APIC
page and hyperv-related stuff. According to the Android Emulator Release
Notes, Revision 26.1.3 (August 2017), "Hypervisor.framework is now
enabled by default on macOS for 32-bit x86 images to improve performance
and macOS compatibility", although we better use with caution for, as the
same Revision warns us, "If you experience issues with it specifically,
please file a bug report...". The code hasn't seen much update in the
last 5 months, so I think that we can further develop the code with
occasional visiting Google's repository to see if there has been any
update.
On top of Google's code, the following changes were made:
- add code to the configure script to support the --enable-hvf argument.
If the OS is Darwin, it checks for presence of HVF in the system. The
patch also adds strings related to HVF in the file qemu-options.hx.
QEMU will only support the modern syntax style '-M accel=hvf' no enable
hvf; the legacy '-enable-hvf' will not be supported.
- fix styling issues
- add glue code to cpus.c
- move HVFX86EmulatorState field to CPUX86State, changing the
the emulation functions to have a parameter with signature 'CPUX86State *'
instead of 'CPUState *' so we don't have to get the 'env'.
Signed-off-by: Sergio Andres Gomez Del Real <Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-2-Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-3-Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-5-Sergio.G.DelReal@gmail.com>
Message-Id: <20170913090522.4022-6-Sergio.G.DelReal@gmail.com>
Message-Id: <20170905035457.3753-7-Sergio.G.DelReal@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-09-13 12:05:09 +03:00
|
|
|
qemu_wait_io_event_common(cpu);
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
void cpus_kick_thread(CPUState *cpu)
|
2011-03-12 19:44:08 +03:00
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
int err;
|
|
|
|
|
2015-08-26 01:19:19 +03:00
|
|
|
if (cpu->thread_kicked) {
|
|
|
|
return;
|
2015-08-18 16:52:09 +03:00
|
|
|
}
|
2015-08-26 01:19:19 +03:00
|
|
|
cpu->thread_kicked = true;
|
2012-05-02 19:00:37 +04:00
|
|
|
err = pthread_kill(cpu->thread->thread, SIG_IPI);
|
2019-01-02 17:16:03 +03:00
|
|
|
if (err && err != ESRCH) {
|
2011-03-12 19:44:08 +03:00
|
|
|
fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
|
|
|
|
exit(1);
|
|
|
|
}
|
2015-08-26 01:19:19 +03:00
|
|
|
#endif
|
|
|
|
}
|
2013-04-09 20:06:53 +04:00
|
|
|
|
2012-05-03 06:34:15 +04:00
|
|
|
void qemu_cpu_kick(CPUState *cpu)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2012-05-03 03:22:49 +04:00
|
|
|
qemu_cond_broadcast(cpu->halt_cond);
|
2020-08-19 17:01:03 +03:00
|
|
|
if (cpus_accel->kick_vcpu_thread) {
|
2020-07-31 13:23:42 +03:00
|
|
|
cpus_accel->kick_vcpu_thread(cpu);
|
2020-07-07 12:18:49 +03:00
|
|
|
} else { /* default */
|
2020-07-31 13:23:42 +03:00
|
|
|
cpus_kick_thread(cpu);
|
2015-08-26 01:19:19 +03:00
|
|
|
}
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2011-02-02 00:15:59 +03:00
|
|
|
void qemu_cpu_kick_self(void)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2013-05-27 07:17:50 +04:00
|
|
|
assert(current_cpu);
|
2020-07-31 13:23:42 +03:00
|
|
|
cpus_kick_thread(current_cpu);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 00:23:49 +04:00
|
|
|
bool qemu_cpu_is_self(CPUState *cpu)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2012-05-02 19:00:37 +04:00
|
|
|
return qemu_thread_is_self(cpu->thread);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2015-01-21 14:09:14 +03:00
|
|
|
bool qemu_in_vcpu_thread(void)
|
2012-09-18 18:30:11 +04:00
|
|
|
{
|
2013-05-27 07:17:50 +04:00
|
|
|
return current_cpu && qemu_cpu_is_self(current_cpu);
|
2012-09-18 18:30:11 +04:00
|
|
|
}
|
|
|
|
|
2015-06-18 19:47:19 +03:00
|
|
|
static __thread bool iothread_locked = false;
|
|
|
|
|
|
|
|
bool qemu_mutex_iothread_locked(void)
|
|
|
|
{
|
|
|
|
return iothread_locked;
|
|
|
|
}
|
|
|
|
|
2017-10-28 09:16:41 +03:00
|
|
|
/*
|
|
|
|
* The BQL is taken from so many places that it is worth profiling the
|
|
|
|
* callers directly, instead of funneling them all through a single function.
|
|
|
|
*/
|
|
|
|
void qemu_mutex_lock_iothread_impl(const char *file, int line)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2020-09-23 13:56:46 +03:00
|
|
|
QemuMutexLockFunc bql_lock = qatomic_read(&qemu_bql_mutex_lock_func);
|
2017-10-28 09:16:41 +03:00
|
|
|
|
tcg: drop global lock during TCG code execution
This finally allows TCG to benefit from the iothread introduction: Drop
the global mutex while running pure TCG CPU code. Reacquire the lock
when entering MMIO or PIO emulation, or when leaving the TCG loop.
We have to revert a few optimization for the current TCG threading
model, namely kicking the TCG thread in qemu_mutex_lock_iothread and not
kicking it in qemu_cpu_kick. We also need to disable RAM block
reordering until we have a more efficient locking mechanism at hand.
Still, a Linux x86 UP guest and my Musicpal ARM model boot fine here.
These numbers demonstrate where we gain something:
20338 jan 20 0 331m 75m 6904 R 99 0.9 0:50.95 qemu-system-arm
20337 jan 20 0 331m 75m 6904 S 20 0.9 0:26.50 qemu-system-arm
The guest CPU was fully loaded, but the iothread could still run mostly
independent on a second core. Without the patch we don't get beyond
32206 jan 20 0 330m 73m 7036 R 82 0.9 1:06.00 qemu-system-arm
32204 jan 20 0 330m 73m 7036 S 21 0.9 0:17.03 qemu-system-arm
We don't benefit significantly, though, when the guest is not fully
loading a host CPU.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Message-Id: <1439220437-23957-10-git-send-email-fred.konrad@greensocs.com>
[FK: Rebase, fix qemu_devices_reset deadlock, rm address_space_* mutex]
Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
[EGC: fixed iothread lock for cpu-exec IRQ handling]
Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: -smp single-threaded fix, clean commit msg, BQL fixes]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Pranith Kumar <bobby.prani@gmail.com>
[PM: target-arm changes]
Acked-by: Peter Maydell <peter.maydell@linaro.org>
2017-02-23 21:29:11 +03:00
|
|
|
g_assert(!qemu_mutex_iothread_locked());
|
2017-10-28 09:16:41 +03:00
|
|
|
bql_lock(&qemu_global_mutex, file, line);
|
2015-06-18 19:47:19 +03:00
|
|
|
iothread_locked = true;
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_mutex_unlock_iothread(void)
|
|
|
|
{
|
tcg: drop global lock during TCG code execution
This finally allows TCG to benefit from the iothread introduction: Drop
the global mutex while running pure TCG CPU code. Reacquire the lock
when entering MMIO or PIO emulation, or when leaving the TCG loop.
We have to revert a few optimization for the current TCG threading
model, namely kicking the TCG thread in qemu_mutex_lock_iothread and not
kicking it in qemu_cpu_kick. We also need to disable RAM block
reordering until we have a more efficient locking mechanism at hand.
Still, a Linux x86 UP guest and my Musicpal ARM model boot fine here.
These numbers demonstrate where we gain something:
20338 jan 20 0 331m 75m 6904 R 99 0.9 0:50.95 qemu-system-arm
20337 jan 20 0 331m 75m 6904 S 20 0.9 0:26.50 qemu-system-arm
The guest CPU was fully loaded, but the iothread could still run mostly
independent on a second core. Without the patch we don't get beyond
32206 jan 20 0 330m 73m 7036 R 82 0.9 1:06.00 qemu-system-arm
32204 jan 20 0 330m 73m 7036 S 21 0.9 0:17.03 qemu-system-arm
We don't benefit significantly, though, when the guest is not fully
loading a host CPU.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Message-Id: <1439220437-23957-10-git-send-email-fred.konrad@greensocs.com>
[FK: Rebase, fix qemu_devices_reset deadlock, rm address_space_* mutex]
Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
[EGC: fixed iothread lock for cpu-exec IRQ handling]
Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: -smp single-threaded fix, clean commit msg, BQL fixes]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Pranith Kumar <bobby.prani@gmail.com>
[PM: target-arm changes]
Acked-by: Peter Maydell <peter.maydell@linaro.org>
2017-02-23 21:29:11 +03:00
|
|
|
g_assert(qemu_mutex_iothread_locked());
|
2015-06-18 19:47:19 +03:00
|
|
|
iothread_locked = false;
|
2010-03-29 23:23:50 +04:00
|
|
|
qemu_mutex_unlock(&qemu_global_mutex);
|
|
|
|
}
|
|
|
|
|
2020-01-30 21:44:17 +03:00
|
|
|
void qemu_cond_wait_iothread(QemuCond *cond)
|
|
|
|
{
|
|
|
|
qemu_cond_wait(cond, &qemu_global_mutex);
|
|
|
|
}
|
|
|
|
|
2020-06-29 12:35:03 +03:00
|
|
|
void qemu_cond_timedwait_iothread(QemuCond *cond, int ms)
|
|
|
|
{
|
|
|
|
qemu_cond_timedwait(cond, &qemu_global_mutex, ms);
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
/* signal CPU creation */
|
|
|
|
void cpu_thread_signal_created(CPUState *cpu)
|
|
|
|
{
|
|
|
|
cpu->created = true;
|
|
|
|
qemu_cond_signal(&qemu_cpu_cond);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* signal CPU destruction */
|
|
|
|
void cpu_thread_signal_destroyed(CPUState *cpu)
|
|
|
|
{
|
|
|
|
cpu->created = false;
|
|
|
|
qemu_cond_signal(&qemu_cpu_cond);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-27 18:09:58 +03:00
|
|
|
static bool all_vcpus_paused(void)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2013-06-25 01:50:24 +04:00
|
|
|
CPUState *cpu;
|
2010-03-29 23:23:50 +04:00
|
|
|
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2013-05-30 00:29:20 +04:00
|
|
|
if (!cpu->stopped) {
|
2016-10-27 18:09:58 +03:00
|
|
|
return false;
|
2011-02-07 14:19:14 +03:00
|
|
|
}
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2016-10-27 18:09:58 +03:00
|
|
|
return true;
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void pause_all_vcpus(void)
|
|
|
|
{
|
2013-06-25 01:50:24 +04:00
|
|
|
CPUState *cpu;
|
2010-03-29 23:23:50 +04:00
|
|
|
|
2013-08-21 19:03:02 +04:00
|
|
|
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false);
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2017-11-29 22:12:15 +03:00
|
|
|
if (qemu_cpu_is_self(cpu)) {
|
|
|
|
qemu_cpu_stop(cpu, true);
|
|
|
|
} else {
|
|
|
|
cpu->stop = true;
|
|
|
|
qemu_cpu_kick(cpu);
|
|
|
|
}
|
2012-02-17 21:31:16 +04:00
|
|
|
}
|
|
|
|
|
2018-02-27 12:52:48 +03:00
|
|
|
/* We need to drop the replay_lock so any vCPU threads woken up
|
|
|
|
* can finish their replay tasks
|
|
|
|
*/
|
|
|
|
replay_mutex_unlock();
|
|
|
|
|
2010-03-29 23:23:50 +04:00
|
|
|
while (!all_vcpus_paused()) {
|
2011-03-12 19:44:02 +03:00
|
|
|
qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2013-05-30 00:29:20 +04:00
|
|
|
qemu_cpu_kick(cpu);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
}
|
2018-02-27 12:52:48 +03:00
|
|
|
|
|
|
|
qemu_mutex_unlock_iothread();
|
|
|
|
replay_mutex_lock();
|
|
|
|
qemu_mutex_lock_iothread();
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2013-04-23 12:29:37 +04:00
|
|
|
void cpu_resume(CPUState *cpu)
|
|
|
|
{
|
|
|
|
cpu->stop = false;
|
|
|
|
cpu->stopped = false;
|
|
|
|
qemu_cpu_kick(cpu);
|
|
|
|
}
|
|
|
|
|
2010-03-29 23:23:50 +04:00
|
|
|
void resume_all_vcpus(void)
|
|
|
|
{
|
2013-06-25 01:50:24 +04:00
|
|
|
CPUState *cpu;
|
2010-03-29 23:23:50 +04:00
|
|
|
|
2020-03-16 11:37:32 +03:00
|
|
|
if (!runstate_is_running()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-21 19:03:02 +04:00
|
|
|
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
|
2013-06-25 01:50:24 +04:00
|
|
|
CPU_FOREACH(cpu) {
|
2013-05-30 00:29:20 +04:00
|
|
|
cpu_resume(cpu);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 18:40:12 +03:00
|
|
|
void cpu_remove_sync(CPUState *cpu)
|
2016-05-12 06:48:13 +03:00
|
|
|
{
|
|
|
|
cpu->stop = true;
|
|
|
|
cpu->unplug = true;
|
|
|
|
qemu_cpu_kick(cpu);
|
2018-01-30 18:40:12 +03:00
|
|
|
qemu_mutex_unlock_iothread();
|
|
|
|
qemu_thread_join(cpu->thread);
|
|
|
|
qemu_mutex_lock_iothread();
|
2016-05-12 06:48:14 +03:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:39:25 +03:00
|
|
|
void cpus_register_accel(const AccelOpsClass *ops)
|
2020-07-31 13:23:42 +03:00
|
|
|
{
|
2021-02-04 19:39:25 +03:00
|
|
|
assert(ops != NULL);
|
|
|
|
assert(ops->create_vcpu_thread != NULL); /* mandatory */
|
|
|
|
cpus_accel = ops;
|
2020-07-31 13:23:42 +03:00
|
|
|
}
|
|
|
|
|
2013-05-27 05:23:24 +04:00
|
|
|
void qemu_init_vcpu(CPUState *cpu)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2019-05-18 23:54:21 +03:00
|
|
|
MachineState *ms = MACHINE(qdev_get_machine());
|
|
|
|
|
|
|
|
cpu->nr_cores = ms->smp.cores;
|
|
|
|
cpu->nr_threads = ms->smp.threads;
|
2012-05-03 01:26:21 +04:00
|
|
|
cpu->stopped = true;
|
2019-03-14 23:06:29 +03:00
|
|
|
cpu->random_seed = qemu_guest_random_seed_thread_part1();
|
2016-01-21 17:15:04 +03:00
|
|
|
|
|
|
|
if (!cpu->as) {
|
|
|
|
/* If the target cpu hasn't set up any address spaces itself,
|
|
|
|
* give it the default one.
|
|
|
|
*/
|
2016-01-21 17:15:04 +03:00
|
|
|
cpu->num_ases = 1;
|
2017-11-23 12:23:32 +03:00
|
|
|
cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory);
|
2016-01-21 17:15:04 +03:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:39:25 +03:00
|
|
|
/* accelerators all implement the AccelOpsClass */
|
2020-08-19 17:01:03 +03:00
|
|
|
g_assert(cpus_accel != NULL && cpus_accel->create_vcpu_thread != NULL);
|
|
|
|
cpus_accel->create_vcpu_thread(cpu);
|
2018-02-09 22:52:38 +03:00
|
|
|
|
|
|
|
while (!cpu->created) {
|
|
|
|
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
|
|
|
|
}
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2011-02-02 00:15:43 +03:00
|
|
|
void cpu_stop_current(void)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2013-05-27 07:17:50 +04:00
|
|
|
if (current_cpu) {
|
2019-01-07 18:23:47 +03:00
|
|
|
current_cpu->stop = true;
|
|
|
|
cpu_exit(current_cpu);
|
2011-02-02 00:15:43 +03:00
|
|
|
}
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2013-07-05 15:49:54 +04:00
|
|
|
int vm_stop(RunState state)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2012-09-18 18:30:11 +04:00
|
|
|
if (qemu_in_vcpu_thread()) {
|
2014-06-05 16:53:58 +04:00
|
|
|
qemu_system_vmstop_request_prepare();
|
2011-07-29 21:26:33 +04:00
|
|
|
qemu_system_vmstop_request(state);
|
2010-03-29 23:23:50 +04:00
|
|
|
/*
|
|
|
|
* FIXME: should not return to device code in case
|
|
|
|
* vm_stop() has been requested.
|
|
|
|
*/
|
2011-02-02 00:15:43 +03:00
|
|
|
cpu_stop_current();
|
2013-07-05 15:49:54 +04:00
|
|
|
return 0;
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
2013-07-05 15:49:54 +04:00
|
|
|
|
2018-03-07 17:42:05 +03:00
|
|
|
return do_vm_stop(state, true);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2017-02-14 20:07:47 +03:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
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()) {
|
2018-08-15 16:37:37 +03:00
|
|
|
qapi_event_send_stop();
|
|
|
|
qapi_event_send_resume();
|
cpus: Fix event order on resume of stopped guest
When resume of a stopped guest immediately runs into block device
errors, the BLOCK_IO_ERROR event is sent before the RESUME event.
Reproducer:
1. Create a scratch image
$ dd if=/dev/zero of=scratch.img bs=1M count=100
Size doesn't actually matter.
2. Prepare blkdebug configuration:
$ cat >blkdebug.conf <<EOF
[inject-error]
event = "write_aio"
errno = "5"
EOF
Note that errno 5 is EIO.
3. Run a guest with an additional scratch disk, i.e. with additional
arguments
-drive if=none,id=scratch-drive,format=raw,werror=stop,file=blkdebug:blkdebug.conf:scratch.img
-device virtio-blk-pci,id=scratch,drive=scratch-drive
The blkdebug part makes all writes to the scratch drive fail with
EIO. The werror=stop pauses the guest on write errors.
4. Connect to the QMP socket e.g. like this:
$ socat UNIX:/your/qmp/socket READLINE,history=$HOME/.qmp_history,prompt='QMP> '
Issue QMP command 'qmp_capabilities':
QMP> { "execute": "qmp_capabilities" }
5. Boot the guest.
6. In the guest, write to the scratch disk, e.g. like this:
# dd if=/dev/zero of=/dev/vdb count=1
Do double-check the device specified with of= is actually the
scratch device!
7. Issue QMP command 'cont':
QMP> { "execute": "cont" }
After step 6, I get a BLOCK_IO_ERROR event followed by a STOP event. Good.
After step 7, I get BLOCK_IO_ERROR, then RESUME, then STOP. Not so
good; I'd expect RESUME, then BLOCK_IO_ERROR, then STOP.
The funny event order confuses libvirt: virsh -r domstate DOMAIN
--reason reports "paused (unknown)" rather than "paused (I/O error)".
The culprit is vm_prepare_start().
/* 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;
When resuming a stopped guest, we take the else branch before we get
to sending RESUME. vm_state_notify() runs virtio_vmstate_change(),
among other things. This restarts I/O, triggering the BLOCK_IO_ERROR
event.
Reshuffle vm_prepare_start() to send the RESUME event earlier.
Fixes RHBZ 1566153.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180423084518.2426-1-armbru@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2018-04-23 11:45:18 +03:00
|
|
|
return -1;
|
2017-02-14 20:07:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We are sending this now, but the CPUs will be resumed shortly later */
|
2018-08-15 16:37:37 +03:00
|
|
|
qapi_event_send_resume();
|
cpus: Fix event order on resume of stopped guest
When resume of a stopped guest immediately runs into block device
errors, the BLOCK_IO_ERROR event is sent before the RESUME event.
Reproducer:
1. Create a scratch image
$ dd if=/dev/zero of=scratch.img bs=1M count=100
Size doesn't actually matter.
2. Prepare blkdebug configuration:
$ cat >blkdebug.conf <<EOF
[inject-error]
event = "write_aio"
errno = "5"
EOF
Note that errno 5 is EIO.
3. Run a guest with an additional scratch disk, i.e. with additional
arguments
-drive if=none,id=scratch-drive,format=raw,werror=stop,file=blkdebug:blkdebug.conf:scratch.img
-device virtio-blk-pci,id=scratch,drive=scratch-drive
The blkdebug part makes all writes to the scratch drive fail with
EIO. The werror=stop pauses the guest on write errors.
4. Connect to the QMP socket e.g. like this:
$ socat UNIX:/your/qmp/socket READLINE,history=$HOME/.qmp_history,prompt='QMP> '
Issue QMP command 'qmp_capabilities':
QMP> { "execute": "qmp_capabilities" }
5. Boot the guest.
6. In the guest, write to the scratch disk, e.g. like this:
# dd if=/dev/zero of=/dev/vdb count=1
Do double-check the device specified with of= is actually the
scratch device!
7. Issue QMP command 'cont':
QMP> { "execute": "cont" }
After step 6, I get a BLOCK_IO_ERROR event followed by a STOP event. Good.
After step 7, I get BLOCK_IO_ERROR, then RESUME, then STOP. Not so
good; I'd expect RESUME, then BLOCK_IO_ERROR, then STOP.
The funny event order confuses libvirt: virsh -r domstate DOMAIN
--reason reports "paused (unknown)" rather than "paused (I/O error)".
The culprit is vm_prepare_start().
/* 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;
When resuming a stopped guest, we take the else branch before we get
to sending RESUME. vm_state_notify() runs virtio_vmstate_change(),
among other things. This restarts I/O, triggering the BLOCK_IO_ERROR
event.
Reshuffle vm_prepare_start() to send the RESUME event earlier.
Fixes RHBZ 1566153.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180423084518.2426-1-armbru@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2018-04-23 11:45:18 +03:00
|
|
|
|
|
|
|
cpu_enable_ticks();
|
|
|
|
runstate_set(RUN_STATE_RUNNING);
|
|
|
|
vm_state_notify(1, RUN_STATE_RUNNING);
|
|
|
|
return 0;
|
2017-02-14 20:07:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void vm_start(void)
|
|
|
|
{
|
|
|
|
if (!vm_prepare_start()) {
|
|
|
|
resume_all_vcpus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 18:18:09 +04:00
|
|
|
/* does a state transition even if the VM is already stopped,
|
|
|
|
current state is forgotten forever */
|
2013-07-05 15:49:54 +04:00
|
|
|
int vm_stop_force_state(RunState state)
|
2011-10-14 18:18:09 +04:00
|
|
|
{
|
|
|
|
if (runstate_is_running()) {
|
2013-07-05 15:49:54 +04:00
|
|
|
return vm_stop(state);
|
2011-10-14 18:18:09 +04:00
|
|
|
} else {
|
2021-04-15 16:33:51 +03:00
|
|
|
int ret;
|
2011-10-14 18:18:09 +04:00
|
|
|
runstate_set(state);
|
2015-11-20 12:34:38 +03:00
|
|
|
|
|
|
|
bdrv_drain_all();
|
2013-07-18 16:52:19 +04:00
|
|
|
/* Make sure to return an error if the flush in a previous vm_stop()
|
|
|
|
* failed. */
|
2021-04-15 16:33:51 +03:00
|
|
|
ret = bdrv_flush_all();
|
|
|
|
trace_vm_stop_flush_all(ret);
|
|
|
|
return ret;
|
2011-10-14 18:18:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 22:17:57 +03:00
|
|
|
void list_cpus(const char *optarg)
|
2010-05-04 23:55:35 +04:00
|
|
|
{
|
|
|
|
/* XXX: implement xxx_cpu_list for targets that still miss it */
|
2012-09-06 00:41:08 +04:00
|
|
|
#if defined(cpu_list)
|
2019-04-17 22:17:57 +03:00
|
|
|
cpu_list();
|
2010-05-04 23:55:35 +04:00
|
|
|
#endif
|
|
|
|
}
|
2011-09-21 23:38:35 +04:00
|
|
|
|
2011-11-22 22:32:37 +04:00
|
|
|
void qmp_memsave(int64_t addr, int64_t size, const char *filename,
|
|
|
|
bool has_cpu, int64_t cpu_index, Error **errp)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
uint32_t l;
|
2012-12-17 09:18:02 +04:00
|
|
|
CPUState *cpu;
|
2011-11-22 22:32:37 +04:00
|
|
|
uint8_t buf[1024];
|
2015-02-08 15:14:38 +03:00
|
|
|
int64_t orig_addr = addr, orig_size = size;
|
2011-11-22 22:32:37 +04:00
|
|
|
|
|
|
|
if (!has_cpu) {
|
|
|
|
cpu_index = 0;
|
|
|
|
}
|
|
|
|
|
2013-02-15 18:41:49 +04:00
|
|
|
cpu = qemu_get_cpu(cpu_index);
|
|
|
|
if (cpu == NULL) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
|
|
|
|
"a CPU number");
|
2011-11-22 22:32:37 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = fopen(filename, "wb");
|
|
|
|
if (!f) {
|
2013-06-07 22:35:06 +04:00
|
|
|
error_setg_file_open(errp, errno, filename);
|
2011-11-22 22:32:37 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (size != 0) {
|
|
|
|
l = sizeof(buf);
|
|
|
|
if (l > size)
|
|
|
|
l = size;
|
2013-10-01 20:19:30 +04:00
|
|
|
if (cpu_memory_rw_debug(cpu, addr, buf, l, 0) != 0) {
|
2015-02-08 15:14:38 +03:00
|
|
|
error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRId64
|
|
|
|
" specified", orig_addr, orig_size);
|
2013-10-01 20:19:30 +04:00
|
|
|
goto exit;
|
|
|
|
}
|
2011-11-22 22:32:37 +04:00
|
|
|
if (fwrite(buf, 1, l, f) != l) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_IO_ERROR);
|
2011-11-22 22:32:37 +04:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
addr += l;
|
|
|
|
size -= l;
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
fclose(f);
|
|
|
|
}
|
2011-11-22 23:26:46 +04:00
|
|
|
|
|
|
|
void qmp_pmemsave(int64_t addr, int64_t size, const char *filename,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
uint32_t l;
|
|
|
|
uint8_t buf[1024];
|
|
|
|
|
|
|
|
f = fopen(filename, "wb");
|
|
|
|
if (!f) {
|
2013-06-07 22:35:06 +04:00
|
|
|
error_setg_file_open(errp, errno, filename);
|
2011-11-22 23:26:46 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (size != 0) {
|
|
|
|
l = sizeof(buf);
|
|
|
|
if (l > size)
|
|
|
|
l = size;
|
2014-04-07 22:28:23 +04:00
|
|
|
cpu_physical_memory_read(addr, buf, l);
|
2011-11-22 23:26:46 +04:00
|
|
|
if (fwrite(buf, 1, l, f) != l) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_IO_ERROR);
|
2011-11-22 23:26:46 +04:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
addr += l;
|
|
|
|
size -= l;
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
fclose(f);
|
|
|
|
}
|
2011-11-23 18:55:53 +04:00
|
|
|
|
|
|
|
void qmp_inject_nmi(Error **errp)
|
|
|
|
{
|
2020-10-05 18:58:44 +03:00
|
|
|
nmi_monitor_handle(monitor_get_cpu_index(monitor_cur()), errp);
|
2011-11-23 18:55:53 +04:00
|
|
|
}
|
2014-07-25 13:56:33 +04:00
|
|
|
|