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"
|
2012-12-17 21:19:49 +04:00
|
|
|
#include "monitor/monitor.h"
|
2022-02-22 17:01:50 +03:00
|
|
|
#include "qemu/coroutine-tls.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"
|
2022-02-03 04:13:28 +03:00
|
|
|
#include "exec/cpu-common.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/thread.h"
|
2022-12-21 16:35:49 +03:00
|
|
|
#include "qemu/main-loop.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 */
|
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
/* The Big QEMU Lock (BQL) */
|
|
|
|
static QemuMutex bql;
|
2019-09-09 16:13:34 +03:00
|
|
|
|
2022-02-03 14:51:06 +03:00
|
|
|
/*
|
|
|
|
* The chosen accelerator is supposed to register this.
|
|
|
|
*/
|
|
|
|
static const AccelOpsClass *cpus_accel;
|
|
|
|
|
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
|
|
|
{
|
2022-01-14 03:43:57 +03:00
|
|
|
return QSIMPLEQ_EMPTY_ATOMIC(&cpu->work_list);
|
2020-06-12 22:02:24 +03:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2022-02-03 03:58:55 +03:00
|
|
|
if (!cpu->halted || cpu_has_work(cpu)) {
|
2012-07-19 19:52:27 +04:00
|
|
|
return false;
|
|
|
|
}
|
2022-02-03 03:58:55 +03:00
|
|
|
if (cpus_accel->cpu_thread_is_idle) {
|
|
|
|
return cpus_accel->cpu_thread_is_idle(cpu);
|
|
|
|
}
|
2012-07-19 19:52:27 +04:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2022-02-03 04:03:57 +03:00
|
|
|
if (cpus_accel->cpus_are_resettable) {
|
|
|
|
return cpus_accel->cpus_are_resettable();
|
|
|
|
}
|
|
|
|
return true;
|
2021-01-26 20:36:47 +03:00
|
|
|
}
|
|
|
|
|
2023-09-15 23:55:33 +03:00
|
|
|
void cpu_exec_reset_hold(CPUState *cpu)
|
|
|
|
{
|
|
|
|
if (cpus_accel->cpu_reset_hold) {
|
|
|
|
cpus_accel->cpu_reset_hold(cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2024-06-20 18:22:12 +03:00
|
|
|
/*
|
|
|
|
* Signal the new virtual time to the accelerator. This is only needed
|
|
|
|
* by accelerators that need to track the changes as we warp time.
|
|
|
|
*/
|
|
|
|
void cpus_set_virtual_clock(int64_t new_time)
|
|
|
|
{
|
|
|
|
if (cpus_accel && cpus_accel->set_virtual_clock) {
|
|
|
|
cpus_accel->set_virtual_clock(new_time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 13:23:42 +03:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-03 23:05:30 +03:00
|
|
|
/*
|
|
|
|
* True if the vm was previously suspended, and has not been woken or reset.
|
|
|
|
*/
|
|
|
|
static int vm_was_suspended;
|
|
|
|
|
|
|
|
void vm_set_suspended(bool suspended)
|
|
|
|
{
|
|
|
|
vm_was_suspended = suspended;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool vm_get_suspended(void)
|
|
|
|
{
|
|
|
|
return vm_was_suspended;
|
|
|
|
}
|
|
|
|
|
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;
|
2024-01-03 23:05:31 +03:00
|
|
|
RunState oldstate = runstate_get();
|
2013-07-05 15:49:54 +04:00
|
|
|
|
2024-01-03 23:05:31 +03:00
|
|
|
if (runstate_is_live(oldstate)) {
|
|
|
|
vm_was_suspended = (oldstate == RUN_STATE_SUSPENDED);
|
2020-03-16 11:37:32 +03:00
|
|
|
runstate_set(state);
|
2010-03-29 23:23:50 +04:00
|
|
|
cpu_disable_ticks();
|
2024-01-03 23:05:31 +03:00
|
|
|
if (oldstate == RUN_STATE_RUNNING) {
|
|
|
|
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;
|
|
|
|
|
2021-12-17 16:46:10 +03:00
|
|
|
/*
|
|
|
|
* ALERT: when modifying this, take care that SIGBUS forwarding in
|
2022-10-14 16:47:14 +03:00
|
|
|
* qemu_prealloc_mem() will continue working as expected.
|
2021-12-17 16:46:10 +03:00
|
|
|
*/
|
2011-02-02 00:15:58 +03:00
|
|
|
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);
|
2024-01-02 18:35:25 +03:00
|
|
|
qemu_mutex_init(&bql);
|
2010-03-29 23:23:50 +04:00
|
|
|
|
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
|
|
|
{
|
2024-01-02 18:35:25 +03:00
|
|
|
do_run_on_cpu(cpu, func, data, &bql);
|
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
|
|
|
{
|
2023-03-03 16:37:51 +03:00
|
|
|
qatomic_set_mb(&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);
|
|
|
|
}
|
2024-01-02 18:35:25 +03:00
|
|
|
qemu_cond_wait(cpu->halt_cond, &bql);
|
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
|
|
|
|
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
|
|
|
{
|
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;
|
2022-10-28 07:57:26 +03:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
int 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);
|
|
|
|
}
|
2022-10-28 07:57:26 +03:00
|
|
|
#else
|
|
|
|
qemu_sem_post(&cpu->sem);
|
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
|
|
|
}
|
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked)
|
2015-06-18 19:47:19 +03:00
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
bool bql_locked(void)
|
2015-06-18 19:47:19 +03:00
|
|
|
{
|
2024-01-02 18:35:25 +03:00
|
|
|
return get_bql_locked();
|
2015-06-18 19:47:19 +03:00
|
|
|
}
|
|
|
|
|
2022-03-03 18:15:46 +03:00
|
|
|
bool qemu_in_main_thread(void)
|
|
|
|
{
|
2024-01-02 18:35:25 +03:00
|
|
|
return bql_locked();
|
2022-03-03 18:15:46 +03:00
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*/
|
2024-01-02 18:35:25 +03:00
|
|
|
void bql_lock_impl(const char *file, int line)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2024-01-02 18:35:25 +03:00
|
|
|
QemuMutexLockFunc bql_lock_fn = qatomic_read(&bql_mutex_lock_func);
|
2017-10-28 09:16:41 +03:00
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
g_assert(!bql_locked());
|
|
|
|
bql_lock_fn(&bql, file, line);
|
|
|
|
set_bql_locked(true);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
void bql_unlock(void)
|
2010-03-29 23:23:50 +04:00
|
|
|
{
|
2024-01-02 18:35:25 +03:00
|
|
|
g_assert(bql_locked());
|
|
|
|
set_bql_locked(false);
|
|
|
|
qemu_mutex_unlock(&bql);
|
2010-03-29 23:23:50 +04:00
|
|
|
}
|
|
|
|
|
2024-01-02 18:35:27 +03:00
|
|
|
void qemu_cond_wait_bql(QemuCond *cond)
|
2020-01-30 21:44:17 +03:00
|
|
|
{
|
2024-01-02 18:35:25 +03:00
|
|
|
qemu_cond_wait(cond, &bql);
|
2020-01-30 21:44:17 +03:00
|
|
|
}
|
|
|
|
|
2024-01-02 18:35:27 +03:00
|
|
|
void qemu_cond_timedwait_bql(QemuCond *cond, int ms)
|
2020-06-29 12:35:03 +03:00
|
|
|
{
|
2024-01-02 18:35:25 +03:00
|
|
|
qemu_cond_timedwait(cond, &bql, ms);
|
2020-06-29 12:35:03 +03:00
|
|
|
}
|
|
|
|
|
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()) {
|
2024-01-02 18:35:25 +03:00
|
|
|
qemu_cond_wait(&qemu_pause_cond, &bql);
|
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
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
bql_unlock();
|
2018-02-27 12:52:48 +03:00
|
|
|
replay_mutex_lock();
|
2024-01-02 18:35:25 +03:00
|
|
|
bql_lock();
|
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);
|
2024-01-02 18:35:25 +03:00
|
|
|
bql_unlock();
|
2018-01-30 18:40:12 +03:00
|
|
|
qemu_thread_join(cpu->thread);
|
2024-01-02 18:35:25 +03:00
|
|
|
bql_lock();
|
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
|
|
|
}
|
|
|
|
|
2022-09-29 14:42:24 +03:00
|
|
|
const AccelOpsClass *cpus_get_accel(void)
|
|
|
|
{
|
|
|
|
/* broken if we call this early */
|
|
|
|
assert(cpus_accel);
|
|
|
|
return cpus_accel;
|
|
|
|
}
|
|
|
|
|
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());
|
|
|
|
|
system/cpus: Fix CPUState.nr_cores' calculation
From CPUState.nr_cores' comment, it represents "number of cores within
this CPU package".
After 003f230e37d7 ("machine: Tweak the order of topology members in
struct CpuTopology"), the meaning of smp.cores changed to "the number of
cores in one die", but this commit missed to change CPUState.nr_cores'
calculation, so that CPUState.nr_cores became wrong and now it
misses to consider numbers of clusters and dies.
At present, only i386 is using CPUState.nr_cores.
But as for i386, which supports die level, the uses of CPUState.nr_cores
are very confusing:
Early uses are based on the meaning of "cores per package" (before die
is introduced into i386), and later uses are based on "cores per die"
(after die's introduction).
This difference is due to that commit a94e1428991f ("target/i386: Add
CPUID.1F generation support for multi-dies PCMachine") misunderstood
that CPUState.nr_cores means "cores per die" when calculated
CPUID.1FH.01H:EBX. After that, the changes in i386 all followed this
wrong understanding.
With the influence of 003f230e37d7 and a94e1428991f, for i386 currently
the result of CPUState.nr_cores is "cores per die", thus the original
uses of CPUState.cores based on the meaning of "cores per package" are
wrong when multiple dies exist:
1. In cpu_x86_cpuid() of target/i386/cpu.c, CPUID.01H:EBX[bits 23:16] is
incorrect because it expects "cpus per package" but now the
result is "cpus per die".
2. In cpu_x86_cpuid() of target/i386/cpu.c, for all leaves of CPUID.04H:
EAX[bits 31:26] is incorrect because they expect "cpus per package"
but now the result is "cpus per die". The error not only impacts the
EAX calculation in cache_info_passthrough case, but also impacts other
cases of setting cache topology for Intel CPU according to cpu
topology (specifically, the incoming parameter "num_cores" expects
"cores per package" in encode_cache_cpuid4()).
3. In cpu_x86_cpuid() of target/i386/cpu.c, CPUID.0BH.01H:EBX[bits
15:00] is incorrect because the EBX of 0BH.01H (core level) expects
"cpus per package", which may be different with 1FH.01H (The reason
is 1FH can support more levels. For QEMU, 1FH also supports die,
1FH.01H:EBX[bits 15:00] expects "cpus per die").
4. In cpu_x86_cpuid() of target/i386/cpu.c, when CPUID.80000001H is
calculated, here "cpus per package" is expected to be checked, but in
fact, now it checks "cpus per die". Though "cpus per die" also works
for this code logic, this isn't consistent with AMD's APM.
5. In cpu_x86_cpuid() of target/i386/cpu.c, CPUID.80000008H:ECX expects
"cpus per package" but it obtains "cpus per die".
6. In simulate_rdmsr() of target/i386/hvf/x86_emu.c, in
kvm_rdmsr_core_thread_count() of target/i386/kvm/kvm.c, and in
helper_rdmsr() of target/i386/tcg/sysemu/misc_helper.c,
MSR_CORE_THREAD_COUNT expects "cpus per package" and "cores per
package", but in these functions, it obtains "cpus per die" and
"cores per die".
On the other hand, these uses are correct now (they are added in/after
a94e1428991f):
1. In cpu_x86_cpuid() of target/i386/cpu.c, topo_info.cores_per_die
meets the actual meaning of CPUState.nr_cores ("cores per die").
2. In cpu_x86_cpuid() of target/i386/cpu.c, vcpus_per_socket (in CPUID.
04H's calculation) considers number of dies, so it's correct.
3. In cpu_x86_cpuid() of target/i386/cpu.c, CPUID.1FH.01H:EBX[bits
15:00] needs "cpus per die" and it gets the correct result, and
CPUID.1FH.02H:EBX[bits 15:00] gets correct "cpus per package".
When CPUState.nr_cores is correctly changed to "cores per package" again
, the above errors will be fixed without extra work, but the "currently"
correct cases will go wrong and need special handling to pass correct
"cpus/cores per die" they want.
Fix CPUState.nr_cores' calculation to fit the original meaning "cores
per package", as well as changing calculation of topo_info.cores_per_die,
vcpus_per_socket and CPUID.1FH.
Fixes: a94e1428991f ("target/i386: Add CPUID.1F generation support for multi-dies PCMachine")
Fixes: 003f230e37d7 ("machine: Tweak the order of topology members in struct CpuTopology")
Signed-off-by: Zhuocheng Ding <zhuocheng.ding@intel.com>
Co-developed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Tested-by: Babu Moger <babu.moger@amd.com>
Tested-by: Yongwei Ma <yongwei.ma@intel.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20231024090323.1859210-4-zhao1.liu@linux.intel.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
2023-10-24 12:03:06 +03:00
|
|
|
cpu->nr_cores = machine_topo_get_cores_per_socket(ms);
|
2019-05-18 23:54:21 +03:00
|
|
|
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) {
|
2024-01-02 18:35:25 +03:00
|
|
|
qemu_cond_wait(&qemu_cpu_cond, &bql);
|
2018-02-09 22:52:38 +03:00
|
|
|
}
|
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.
|
2024-01-03 23:05:31 +03:00
|
|
|
* Returns 0 if the vCPUs should be restarted, -1 on an error condition,
|
|
|
|
* and 1 otherwise.
|
2017-02-14 20:07:47 +03:00
|
|
|
*/
|
2022-03-03 04:28:33 +03:00
|
|
|
int vm_prepare_start(bool step_pending)
|
2017-02-14 20:07:47 +03:00
|
|
|
{
|
2024-01-03 23:05:31 +03:00
|
|
|
int ret = vm_was_suspended ? 1 : 0;
|
|
|
|
RunState state = vm_was_suspended ? RUN_STATE_SUSPENDED : RUN_STATE_RUNNING;
|
2017-02-14 20:07:47 +03:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-03-03 04:28:33 +03:00
|
|
|
/*
|
|
|
|
* WHPX accelerator needs to know whether we are going to step
|
|
|
|
* any CPUs, before starting the first one.
|
|
|
|
*/
|
|
|
|
if (cpus_accel->synchronize_pre_resume) {
|
|
|
|
cpus_accel->synchronize_pre_resume(step_pending);
|
|
|
|
}
|
|
|
|
|
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();
|
2024-01-03 23:05:31 +03:00
|
|
|
runstate_set(state);
|
|
|
|
vm_state_notify(1, state);
|
|
|
|
vm_was_suspended = false;
|
|
|
|
return ret;
|
2017-02-14 20:07:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void vm_start(void)
|
|
|
|
{
|
2022-03-03 04:28:33 +03:00
|
|
|
if (!vm_prepare_start(false)) {
|
2017-02-14 20:07:47 +03:00
|
|
|
resume_all_vcpus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-03 23:05:33 +03:00
|
|
|
void vm_resume(RunState state)
|
|
|
|
{
|
|
|
|
if (runstate_is_live(state)) {
|
|
|
|
vm_start();
|
|
|
|
} else {
|
|
|
|
runstate_set(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2024-01-03 23:05:31 +03:00
|
|
|
if (runstate_is_live(runstate_get())) {
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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) {
|
2024-05-13 17:17:01 +03:00
|
|
|
error_setg(errp, "writing memory to '%s' failed",
|
|
|
|
filename);
|
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) {
|
2024-05-13 17:17:01 +03:00
|
|
|
error_setg(errp, "writing memory to '%s' failed",
|
|
|
|
filename);
|
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
|
|
|
|