mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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
|
||||
|
||||
+1
-1
@@ -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 ? */
|
||||
|
||||
+42
-44
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+77
-25
@@ -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);
|
||||
|
||||
|
||||
+4
-2
@@ -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(),
|
||||
};
|
||||
|
||||
|
||||
+3
-3
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ static void handle_event(int event)
|
||||
}
|
||||
|
||||
if (event & PVPANIC_PANICKED) {
|
||||
qemu_system_guest_panicked();
|
||||
qemu_system_guest_panicked(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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:
|
||||
#
|
||||
|
||||
+4
-2
@@ -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:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user