* GUEST_PANICKED improvements (Anton)
* vCont gdbstub rewrite (Claudio) * Fix CPU creation with -device (Liyang) * Logging fixes for pty chardevs (Ed) * Makefile "move if changed" fix (Lin) * First part of cpu_exec refactoring (me) * SVM emulation fix (me) * apic_delivered fix (Pavel) * "info ioapic" fix (Peter) * qemu-nbd socket activation (Richard) * QOMification of mcf_uart (Thomas) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQEcBAABAgAGBQJYpeNbAAoJEL/70l94x66DIC4H/0I1WChmdOKqMBOuHe5yGIqy YZUpEmbUMG9A8Idh6uuVaQni6mYcMpJwq3zNYkNFEAodNzoKsh475gyV3ay5SnY/ s8x6KeCfsVD5UgpQQH9Q3kVr+4QfdtPCqbkoXq4rMeA0293J6sq/+cTqwACJuY9T yCdrFhFoRO6B/dv/c/vMx7XqOwTNwOhJZUPc/ZvgZM4llB+wNaR1G/eRjcAVnLG8 JZp3bDqHkqoe2aIauYfW59LVQ/Vjejxn3yCXyvj8gk3OG81SEziKX6jM/ls29C2V 2eu6+f8wvOW0plj+zE9UcXe/7ThMYvv7TwhnhIaPOsLDBrVFtT8VAOW7KpuLN54= =3ucZ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging * GUEST_PANICKED improvements (Anton) * vCont gdbstub rewrite (Claudio) * Fix CPU creation with -device (Liyang) * Logging fixes for pty chardevs (Ed) * Makefile "move if changed" fix (Lin) * First part of cpu_exec refactoring (me) * SVM emulation fix (me) * apic_delivered fix (Pavel) * "info ioapic" fix (Peter) * qemu-nbd socket activation (Richard) * QOMification of mcf_uart (Thomas) # gpg: Signature made Thu 16 Feb 2017 17:37:31 GMT # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (23 commits) target-i386: correctly propagate retaddr into SVM helpers vl: log available guest crash information report guest crash information in GUEST_PANICKED event i386/cpu: add crash-information QOM property Makefile: avoid leaving the temporary QEMU_PKGVERSION header file vl: Move the cpu_synchronize_all_post_init() after generic devices initialization qemu-nbd: Implement socket activation. qemu-doc: Clarify that -vga std is now the default cpu-exec: remove outermost infinite loop cpu-exec: avoid repeated sigsetjmp on interrupts cpu-exec: avoid cpu_loop_exit in cpu_handle_interrupt cpu-exec: tighten barrier on TCG_EXIT_REQUESTED cpu-exec: fix icount out-of-bounds access hw/char/mcf_uart: QOMify the ColdFire UART gdbstub: Fix vCont behaviour move vm_start to cpus.c char: drop data written to a disconnected pty apic: reset apic_delivered global variable on machine reset qemu-char: socket backend: disconnect on write error test-vmstate: remove yield_until_fd_readable ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ad584d37f2
6
Makefile
6
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
|
||||
|
@ -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);
|
||||
|
@ -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 ? */
|
||||
|
86
cpu-exec.c
86
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,23 +484,23 @@ 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) {
|
||||
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;
|
||||
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,
|
||||
@ -542,7 +544,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:
|
||||
@ -552,11 +554,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:
|
||||
@ -566,6 +568,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 +578,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;
|
||||
}
|
||||
}
|
||||
@ -621,42 +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) {
|
||||
TranslationBlock *tb, *last_tb = NULL;
|
||||
int tb_exit = 0;
|
||||
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (cpu_handle_exception(cpu, &ret)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
cpu_handle_interrupt(cpu, &last_tb);
|
||||
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 {
|
||||
/* 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();
|
||||
|
42
cpus.c
42
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)
|
||||
|
207
gdbstub.c
207
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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(),
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -42,7 +42,7 @@ static void handle_event(int event)
|
||||
}
|
||||
|
||||
if (event & PVPANIC_PANICKED) {
|
||||
qemu_system_guest_panicked();
|
||||
qemu_system_guest_panicked(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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,11 +61,12 @@ 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);
|
||||
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);
|
||||
|
@ -2000,8 +2000,9 @@ 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_system_guest_panicked(cpu_get_crash_info(cpu));
|
||||
qemu_mutex_unlock_iothread();
|
||||
ret = 0;
|
||||
break;
|
||||
|
@ -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:
|
||||
#
|
||||
|
@ -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:
|
||||
|
172
qemu-nbd.c
172
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;
|
||||
|
||||
|
@ -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
|
||||
|
11
qom/cpu.c
11
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)
|
||||
{
|
||||
|
@ -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++) {
|
||||
@ -3684,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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
56
vl.c
56
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 */
|
||||
|
||||
@ -1707,18 +1679,34 @@ void qemu_system_reset(bool report)
|
||||
cpu_synchronize_all_post_reset();
|
||||
}
|
||||
|
||||
void qemu_system_guest_panicked(void)
|
||||
void qemu_system_guest_panicked(GuestPanicInformation *info)
|
||||
{
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed\n");
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_system_reset_request(void)
|
||||
@ -4490,8 +4478,6 @@ int main(int argc, char **argv, char **envp)
|
||||
|
||||
audio_init();
|
||||
|
||||
cpu_synchronize_all_post_init();
|
||||
|
||||
if (hax_enabled()) {
|
||||
hax_sync_vcpus();
|
||||
}
|
||||
@ -4517,6 +4503,8 @@ int main(int argc, char **argv, char **envp)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu_synchronize_all_post_init();
|
||||
|
||||
numa_post_machine_init();
|
||||
|
||||
rom_reset_order_override();
|
||||
|
Loading…
Reference in New Issue
Block a user