* Record-replay lockstep execution, log dumper and fixes (Alex, Pavel)
* SCSI fix to pass maximum transfer size (Daniel Barboza) * chardev fixes and improved iothread support (Daniel Berrangé, Peter) * checkpatch tweak (Eric) * make help tweak (Marc-André) * make more PCI NICs available with -net or -nic (myself) * change default q35 NIC to e1000e (myself) * SCSI support for NDOB bit (myself) * membarrier system call support (myself) * SuperIO refactoring (Philippe) * miscellaneous cleanups and fixes (Thomas) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQEcBAABAgAGBQJapqaMAAoJEL/70l94x66DQoUH/Rvg+a8giz/SrEA4P8D3Cb2z 4GNbNUUoy4oU0ltD5IAMskMwpOsvl1batE0D+pKIlfO9NV4+Cj2kpgo0p9TxoYqM VCby3wRtx27zb5nVytC6M++iIKXmeEMqXmFw61I6umddNPSl4IR3hiHEE0DM+7dV UPIOvJeEiazyQaw3Iw+ZctNn8dDBKc/+6oxP9xRcYTaZ6hB4G9RZkqGNNSLcJkk7 R0UotdjzIZhyWMOkjIwlpTF4sWv8gsYUV4bPYKMYho5B0Obda2dBM3I1kpA8yDa/ xZ5lheOaAVBZvM5aMIcaQPa65MO9hLyXFmhMOgyfpJhLBBz6Qpa4OLLI6DeTN+0= =UAgA -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging * Record-replay lockstep execution, log dumper and fixes (Alex, Pavel) * SCSI fix to pass maximum transfer size (Daniel Barboza) * chardev fixes and improved iothread support (Daniel Berrangé, Peter) * checkpatch tweak (Eric) * make help tweak (Marc-André) * make more PCI NICs available with -net or -nic (myself) * change default q35 NIC to e1000e (myself) * SCSI support for NDOB bit (myself) * membarrier system call support (myself) * SuperIO refactoring (Philippe) * miscellaneous cleanups and fixes (Thomas) # gpg: Signature made Mon 12 Mar 2018 16:10:52 GMT # gpg: using RSA key BFFBD25F78C7AE83 # 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: (69 commits) tcg: fix cpu_io_recompile replay: update documentation replay: save vmstate of the asynchronous events replay: don't process async events when warping the clock scripts/replay-dump.py: replay log dumper replay: avoid recursive call of checkpoints replay: check return values of fwrite replay: push replay_mutex_lock up the call tree replay: don't destroy mutex at exit replay: make locking visible outside replay code replay/replay-internal.c: track holding of replay_lock replay/replay.c: bump REPLAY_VERSION again replay: save prior value of the host clock replay: added replay log format description replay: fix save/load vm for non-empty queue replay: fixed replay_enable_events replay: fix processing async events cpu-exec: fix exception_index handling hw/i386/pc: Factor out the superio code hw/alpha/dp264: Use the TYPE_SMC37C669_SUPERIO ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org> # Conflicts: # default-configs/i386-softmmu.mak # default-configs/x86_64-softmmu.mak
This commit is contained in:
commit
3788c7b6e5
20
MAINTAINERS
20
MAINTAINERS
@ -127,7 +127,6 @@ Alpha
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: target/alpha/
|
||||
F: hw/alpha/
|
||||
F: tests/tcg/alpha/
|
||||
F: disas/alpha.c
|
||||
|
||||
@ -413,6 +412,12 @@ F: include/*/*win32*
|
||||
X: qga/*win32*
|
||||
F: qemu.nsi
|
||||
|
||||
Alpha Machines
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: hw/alpha/
|
||||
F: hw/isa/smc37c669-superio.c
|
||||
|
||||
ARM Machines
|
||||
------------
|
||||
Allwinner-a10
|
||||
@ -700,6 +705,8 @@ Fulong 2E
|
||||
M: Yongbok Kim <yongbok.kim@mips.com>
|
||||
S: Odd Fixes
|
||||
F: hw/mips/mips_fulong2e.c
|
||||
F: hw/isa/vt82c686.c
|
||||
F: include/hw/isa/vt82c686.h
|
||||
|
||||
Boston
|
||||
M: Paul Burton <paul.burton@mips.com>
|
||||
@ -776,9 +783,10 @@ F: hw/ppc/prep_systemio.c
|
||||
F: hw/ppc/rs6000_mc.c
|
||||
F: hw/pci-host/prep.[hc]
|
||||
F: hw/isa/i82378.c
|
||||
F: hw/isa/pc87312.[hc]
|
||||
F: hw/isa/pc87312.c
|
||||
F: hw/dma/i82374.c
|
||||
F: hw/timer/m48t59-isa.c
|
||||
F: include/hw/isa/pc87312.h
|
||||
F: include/hw/timer/m48t59.h
|
||||
F: pc-bios/ppc_rom.bin
|
||||
|
||||
@ -924,7 +932,7 @@ M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Supported
|
||||
F: hw/char/debugcon.c
|
||||
F: hw/char/parallel.c
|
||||
F: hw/char/parallel*
|
||||
F: hw/char/serial*
|
||||
F: hw/dma/i8257*
|
||||
F: hw/i2c/pm_smbus.c
|
||||
@ -932,6 +940,7 @@ F: hw/input/pckbd.c
|
||||
F: hw/intc/apic*
|
||||
F: hw/intc/ioapic*
|
||||
F: hw/intc/i8259*
|
||||
F: hw/isa/isa-superio.c
|
||||
F: hw/misc/debugexit.c
|
||||
F: hw/misc/pc-testdev.c
|
||||
F: hw/timer/hpet*
|
||||
@ -939,8 +948,11 @@ F: hw/timer/i8254*
|
||||
F: hw/timer/mc146818rtc*
|
||||
F: hw/watchdog/wdt_ib700.c
|
||||
F: include/hw/display/vga.h
|
||||
F: include/hw/char/parallel.h
|
||||
F: include/hw/dma/i8257.h
|
||||
F: include/hw/i2c/pm_smbus.h
|
||||
F: include/hw/isa/i8257.h
|
||||
F: include/hw/input/i8042.h
|
||||
F: include/hw/isa/superio.h
|
||||
F: include/hw/timer/hpet.h
|
||||
F: include/hw/timer/i8254*
|
||||
F: include/hw/timer/mc146818rtc*
|
||||
|
23
Makefile
23
Makefile
@ -438,21 +438,23 @@ all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
|
||||
qemu-version.h: FORCE
|
||||
$(call quiet-command, \
|
||||
(cd $(SRC_PATH); \
|
||||
printf '#define QEMU_PKGVERSION '; \
|
||||
if test -n "$(PKGVERSION)"; then \
|
||||
printf '"$(PKGVERSION)"\n'; \
|
||||
pkgvers="$(PKGVERSION)"; \
|
||||
else \
|
||||
if test -d .git; then \
|
||||
printf '" ('; \
|
||||
git describe --match 'v*' 2>/dev/null | tr -d '\n'; \
|
||||
pkgvers=$$(git describe --match 'v*' 2>/dev/null | tr -d '\n');\
|
||||
if ! git diff-index --quiet HEAD &>/dev/null; then \
|
||||
printf -- '-dirty'; \
|
||||
pkgvers="$${pkgvers}-dirty"; \
|
||||
fi; \
|
||||
printf ')"\n'; \
|
||||
else \
|
||||
printf '""\n'; \
|
||||
fi; \
|
||||
fi) > $@.tmp)
|
||||
fi; \
|
||||
printf "#define QEMU_PKGVERSION \"$${pkgvers}\"\n"; \
|
||||
if test -n "$${pkgvers}"; then \
|
||||
printf '#define QEMU_FULL_VERSION QEMU_VERSION " (" QEMU_PKGVERSION ")"\n'; \
|
||||
else \
|
||||
printf '#define QEMU_FULL_VERSION QEMU_VERSION\n'; \
|
||||
fi; \
|
||||
) > $@.tmp)
|
||||
$(call quiet-command, if ! cmp -s $@ $@.tmp; then \
|
||||
mv $@.tmp $@; \
|
||||
else \
|
||||
@ -1050,6 +1052,9 @@ include $(SRC_PATH)/tests/vm/Makefile.include
|
||||
help:
|
||||
@echo 'Generic targets:'
|
||||
@echo ' all - Build all'
|
||||
ifdef CONFIG_MODULES
|
||||
@echo ' modules - Build all modules'
|
||||
endif
|
||||
@echo ' dir/file.o - Build specified target only'
|
||||
@echo ' install - Install QEMU, documentation and tools'
|
||||
@echo ' ctags/TAGS - Generate tags file for editors'
|
||||
|
@ -585,6 +585,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
else {
|
||||
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
replay_interrupt();
|
||||
cpu->exception_index = -1;
|
||||
*last_tb = NULL;
|
||||
}
|
||||
/* The target hook may have updated the 'cpu->interrupt_request';
|
||||
@ -606,7 +607,9 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
if (unlikely(atomic_read(&cpu->exit_request)
|
||||
|| (use_icount && cpu->icount_decr.u16.low + cpu->icount_extra == 0))) {
|
||||
atomic_set(&cpu->exit_request, 0);
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
if (cpu->exception_index == -1) {
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1728,7 +1728,8 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
#endif
|
||||
TranslationBlock *tb;
|
||||
uint32_t n;
|
||||
uint32_t n, flags;
|
||||
target_ulong pc, cs_base;
|
||||
|
||||
tb_lock();
|
||||
tb = tb_find_pc(retaddr);
|
||||
@ -1766,8 +1767,14 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
cpu_abort(cpu, "TB too big during recompile");
|
||||
}
|
||||
|
||||
/* Adjust the execution state of the next TB. */
|
||||
cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | n;
|
||||
pc = tb->pc;
|
||||
cs_base = tb->cs_base;
|
||||
flags = tb->flags;
|
||||
tb_phys_invalidate(tb, -1);
|
||||
|
||||
/* Execute one IO instruction without caching
|
||||
instead of creating large TB. */
|
||||
cpu->cflags_next_tb = curr_cflags() | CF_LAST_IO | CF_NOCACHE | 1;
|
||||
|
||||
if (tb->cflags & CF_NOCACHE) {
|
||||
if (tb->orig_tb) {
|
||||
@ -1778,6 +1785,11 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
tb_remove(tb);
|
||||
}
|
||||
|
||||
/* Generate new TB instead of the current one. */
|
||||
/* FIXME: In theory this could raise an exception. In practice
|
||||
we have already translated the block once so it's probably ok. */
|
||||
tb_gen_code(cpu, pc, cs_base, flags, curr_cflags() | CF_LAST_IO | n);
|
||||
|
||||
/* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
|
||||
* the first in the TB) then we end up generating a whole new TB and
|
||||
* repeating the fault, which is horribly inefficient.
|
||||
|
@ -649,7 +649,7 @@ void cpu_loop(CPUSPARCState *env)
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
|
||||
printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
|
||||
"\n" QEMU_COPYRIGHT "\n"
|
||||
"usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
|
||||
"BSD CPU emulator (compiled for %s emulation)\n"
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "qemu/option.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "chardev/char-mux.h"
|
||||
|
||||
/* MUX driver for serial I/O splitting */
|
||||
@ -230,14 +231,12 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
|
||||
}
|
||||
}
|
||||
|
||||
bool muxes_realized;
|
||||
|
||||
void mux_chr_send_all_event(Chardev *chr, int event)
|
||||
{
|
||||
MuxChardev *d = MUX_CHARDEV(chr);
|
||||
int i;
|
||||
|
||||
if (!muxes_realized) {
|
||||
if (!machine_init_done) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -327,7 +326,7 @@ static void qemu_chr_open_mux(Chardev *chr,
|
||||
/* only default to opened state if we've realized the initial
|
||||
* set of muxes
|
||||
*/
|
||||
*be_opened = muxes_realized;
|
||||
*be_opened = machine_init_done;
|
||||
qemu_chr_fe_init(&d->chr, drv, errp);
|
||||
}
|
||||
|
||||
@ -347,6 +346,31 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
|
||||
mux->chardev = g_strdup(chardev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after processing of default and command-line-specified
|
||||
* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
|
||||
* to a mux chardev. This is done here to ensure that
|
||||
* output/prompts/banners are only displayed for the FE that has
|
||||
* focus when initial command-line processing/machine init is
|
||||
* completed.
|
||||
*
|
||||
* After this point, any new FE attached to any new or existing
|
||||
* mux will receive CHR_EVENT_OPENED notifications for the BE
|
||||
* immediately.
|
||||
*/
|
||||
static int open_muxes(Chardev *chr)
|
||||
{
|
||||
/* send OPENED to all already-attached FEs */
|
||||
mux_chr_send_all_event(chr, CHR_EVENT_OPENED);
|
||||
/*
|
||||
* mark mux as OPENED so any new FEs will immediately receive
|
||||
* OPENED event
|
||||
*/
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void char_mux_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||
@ -357,6 +381,7 @@ static void char_mux_class_init(ObjectClass *oc, void *data)
|
||||
cc->chr_accept_input = mux_chr_accept_input;
|
||||
cc->chr_add_watch = mux_chr_add_watch;
|
||||
cc->chr_be_event = mux_chr_be_event;
|
||||
cc->chr_machine_done = open_muxes;
|
||||
}
|
||||
|
||||
static const TypeInfo char_mux_type_info = {
|
||||
|
@ -40,6 +40,11 @@
|
||||
|
||||
#define TCP_MAX_FDS 16
|
||||
|
||||
typedef struct {
|
||||
char buf[21];
|
||||
size_t buflen;
|
||||
} TCPChardevTelnetInit;
|
||||
|
||||
typedef struct {
|
||||
Chardev parent;
|
||||
QIOChannel *ioc; /* Client I/O channel */
|
||||
@ -60,6 +65,8 @@ typedef struct {
|
||||
bool is_listen;
|
||||
bool is_telnet;
|
||||
bool is_tn3270;
|
||||
GSource *telnet_source;
|
||||
TCPChardevTelnetInit *telnet_init;
|
||||
|
||||
GSource *reconnect_timer;
|
||||
int64_t reconnect_time;
|
||||
@ -70,6 +77,7 @@ typedef struct {
|
||||
OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
|
||||
|
||||
static gboolean socket_reconnect_timeout(gpointer opaque);
|
||||
static void tcp_chr_telnet_init(Chardev *chr);
|
||||
|
||||
static void tcp_chr_reconn_timer_cancel(SocketChardev *s)
|
||||
{
|
||||
@ -423,8 +431,8 @@ static void tcp_chr_disconnect(Chardev *chr)
|
||||
tcp_chr_free_connection(chr);
|
||||
|
||||
if (s->listener) {
|
||||
qio_net_listener_set_client_func(s->listener, tcp_chr_accept,
|
||||
chr, NULL);
|
||||
qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
|
||||
chr, NULL, chr->gcontext);
|
||||
}
|
||||
update_disconnected_filename(s);
|
||||
if (emit_close) {
|
||||
@ -450,7 +458,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
len = s->max_size;
|
||||
}
|
||||
size = tcp_chr_recv(chr, (void *)buf, len);
|
||||
if (size == 0 || size == -1) {
|
||||
if (size == 0 || (size == -1 && errno != EAGAIN)) {
|
||||
/* connection closed */
|
||||
tcp_chr_disconnect(chr);
|
||||
} else if (size > 0) {
|
||||
@ -556,10 +564,33 @@ static void tcp_chr_connect(void *opaque)
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
static void tcp_chr_telnet_destroy(SocketChardev *s)
|
||||
{
|
||||
if (s->telnet_source) {
|
||||
g_source_destroy(s->telnet_source);
|
||||
g_source_unref(s->telnet_source);
|
||||
s->telnet_source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void tcp_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
|
||||
if (s->listener) {
|
||||
/*
|
||||
* It's possible that chardev context is changed in
|
||||
* qemu_chr_be_update_read_handlers(). Reset it for QIO net
|
||||
* listener if there is.
|
||||
*/
|
||||
qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
|
||||
chr, NULL, chr->gcontext);
|
||||
}
|
||||
|
||||
if (s->telnet_source) {
|
||||
tcp_chr_telnet_init(CHARDEV(s));
|
||||
}
|
||||
|
||||
if (!s->connected) {
|
||||
return;
|
||||
}
|
||||
@ -573,32 +604,30 @@ static void tcp_chr_update_read_handler(Chardev *chr)
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Chardev *chr;
|
||||
char buf[21];
|
||||
size_t buflen;
|
||||
} TCPChardevTelnetInit;
|
||||
|
||||
static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
|
||||
GIOCondition cond G_GNUC_UNUSED,
|
||||
gpointer user_data)
|
||||
{
|
||||
TCPChardevTelnetInit *init = user_data;
|
||||
SocketChardev *s = user_data;
|
||||
Chardev *chr = CHARDEV(s);
|
||||
TCPChardevTelnetInit *init = s->telnet_init;
|
||||
ssize_t ret;
|
||||
|
||||
assert(init);
|
||||
|
||||
ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
ret = 0;
|
||||
} else {
|
||||
tcp_chr_disconnect(init->chr);
|
||||
tcp_chr_disconnect(chr);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
init->buflen -= ret;
|
||||
|
||||
if (init->buflen == 0) {
|
||||
tcp_chr_connect(init->chr);
|
||||
tcp_chr_connect(chr);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -607,16 +636,30 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
end:
|
||||
g_free(init);
|
||||
g_free(s->telnet_init);
|
||||
s->telnet_init = NULL;
|
||||
g_source_unref(s->telnet_source);
|
||||
s->telnet_source = NULL;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void tcp_chr_telnet_init(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
|
||||
TCPChardevTelnetInit *init;
|
||||
size_t n = 0;
|
||||
|
||||
/* Destroy existing task */
|
||||
tcp_chr_telnet_destroy(s);
|
||||
|
||||
if (s->telnet_init) {
|
||||
/* We are possibly during a handshake already */
|
||||
goto cont;
|
||||
}
|
||||
|
||||
s->telnet_init = g_new0(TCPChardevTelnetInit, 1);
|
||||
init = s->telnet_init;
|
||||
|
||||
#define IACSET(x, a, b, c) \
|
||||
do { \
|
||||
x[n++] = a; \
|
||||
@ -624,7 +667,6 @@ static void tcp_chr_telnet_init(Chardev *chr)
|
||||
x[n++] = c; \
|
||||
} while (0)
|
||||
|
||||
init->chr = chr;
|
||||
if (!s->is_tn3270) {
|
||||
init->buflen = 12;
|
||||
/* Prep the telnet negotion to put telnet in binary,
|
||||
@ -647,10 +689,11 @@ static void tcp_chr_telnet_init(Chardev *chr)
|
||||
|
||||
#undef IACSET
|
||||
|
||||
qio_channel_add_watch(
|
||||
s->ioc, G_IO_OUT,
|
||||
tcp_chr_telnet_init_io,
|
||||
init, NULL);
|
||||
cont:
|
||||
s->telnet_source = qio_channel_add_watch_source(s->ioc, G_IO_OUT,
|
||||
tcp_chr_telnet_init_io,
|
||||
s, NULL,
|
||||
chr->gcontext);
|
||||
}
|
||||
|
||||
|
||||
@ -707,7 +750,7 @@ static void tcp_chr_tls_init(Chardev *chr)
|
||||
tcp_chr_tls_handshake,
|
||||
chr,
|
||||
NULL,
|
||||
NULL);
|
||||
chr->gcontext);
|
||||
}
|
||||
|
||||
|
||||
@ -743,7 +786,8 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
|
||||
qio_channel_set_delay(s->ioc, false);
|
||||
}
|
||||
if (s->listener) {
|
||||
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
|
||||
qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
|
||||
NULL, chr->gcontext);
|
||||
}
|
||||
|
||||
if (s->tls_creds) {
|
||||
@ -823,8 +867,11 @@ static void char_socket_finalize(Object *obj)
|
||||
tcp_chr_free_connection(chr);
|
||||
tcp_chr_reconn_timer_cancel(s);
|
||||
qapi_free_SocketAddress(s->addr);
|
||||
tcp_chr_telnet_destroy(s);
|
||||
g_free(s->telnet_init);
|
||||
if (s->listener) {
|
||||
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
|
||||
qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
|
||||
NULL, chr->gcontext);
|
||||
object_unref(OBJECT(s->listener));
|
||||
}
|
||||
if (s->tls_creds) {
|
||||
@ -854,11 +901,22 @@ cleanup:
|
||||
object_unref(OBJECT(sioc));
|
||||
}
|
||||
|
||||
static void tcp_chr_connect_async(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
QIOChannelSocket *sioc;
|
||||
|
||||
sioc = qio_channel_socket_new();
|
||||
tcp_chr_set_client_ioc_name(chr, sioc);
|
||||
qio_channel_socket_connect_async(sioc, s->addr,
|
||||
qemu_chr_socket_connected,
|
||||
chr, NULL, chr->gcontext);
|
||||
}
|
||||
|
||||
static gboolean socket_reconnect_timeout(gpointer opaque)
|
||||
{
|
||||
Chardev *chr = CHARDEV(opaque);
|
||||
SocketChardev *s = SOCKET_CHARDEV(opaque);
|
||||
QIOChannelSocket *sioc;
|
||||
|
||||
g_source_unref(s->reconnect_timer);
|
||||
s->reconnect_timer = NULL;
|
||||
@ -867,11 +925,7 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
|
||||
return false;
|
||||
}
|
||||
|
||||
sioc = qio_channel_socket_new();
|
||||
tcp_chr_set_client_ioc_name(chr, sioc);
|
||||
qio_channel_socket_connect_async(sioc, s->addr,
|
||||
qemu_chr_socket_connected,
|
||||
chr, NULL, NULL);
|
||||
tcp_chr_connect_async(chr);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -950,13 +1004,8 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
s->reconnect_time = reconnect;
|
||||
}
|
||||
|
||||
if (s->reconnect_time) {
|
||||
sioc = qio_channel_socket_new();
|
||||
tcp_chr_set_client_ioc_name(chr, sioc);
|
||||
qio_channel_socket_connect_async(sioc, s->addr,
|
||||
qemu_chr_socket_connected,
|
||||
chr, NULL, NULL);
|
||||
} else {
|
||||
/* If reconnect_time is set, will do that in chr_machine_done. */
|
||||
if (!s->reconnect_time) {
|
||||
if (s->is_listen) {
|
||||
char *name;
|
||||
s->listener = qio_net_listener_new();
|
||||
@ -980,8 +1029,10 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
return;
|
||||
}
|
||||
if (!s->ioc) {
|
||||
qio_net_listener_set_client_func(s->listener, tcp_chr_accept,
|
||||
chr, NULL);
|
||||
qio_net_listener_set_client_func_full(s->listener,
|
||||
tcp_chr_accept,
|
||||
chr, NULL,
|
||||
chr->gcontext);
|
||||
}
|
||||
} else if (qemu_chr_wait_connected(chr, errp) < 0) {
|
||||
goto error;
|
||||
@ -1103,6 +1154,17 @@ char_socket_get_connected(Object *obj, Error **errp)
|
||||
return s->connected;
|
||||
}
|
||||
|
||||
static int tcp_chr_machine_done_hook(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
|
||||
if (s->reconnect_time) {
|
||||
tcp_chr_connect_async(chr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void char_socket_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||
@ -1118,6 +1180,7 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
|
||||
cc->chr_add_client = tcp_chr_add_client;
|
||||
cc->chr_add_watch = tcp_chr_add_watch;
|
||||
cc->chr_update_read_handler = tcp_chr_update_read_handler;
|
||||
cc->chr_machine_done = tcp_chr_machine_done_hook;
|
||||
|
||||
object_class_property_add(oc, "addr", "SocketAddress",
|
||||
char_socket_get_addr, NULL,
|
||||
|
@ -281,40 +281,31 @@ static const TypeInfo char_type_info = {
|
||||
.class_init = char_class_init,
|
||||
};
|
||||
|
||||
/**
|
||||
* Called after processing of default and command-line-specified
|
||||
* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
|
||||
* to a mux chardev. This is done here to ensure that
|
||||
* output/prompts/banners are only displayed for the FE that has
|
||||
* focus when initial command-line processing/machine init is
|
||||
* completed.
|
||||
*
|
||||
* After this point, any new FE attached to any new or existing
|
||||
* mux will receive CHR_EVENT_OPENED notifications for the BE
|
||||
* immediately.
|
||||
*/
|
||||
static int open_muxes(Object *child, void *opaque)
|
||||
static int chardev_machine_done_notify_one(Object *child, void *opaque)
|
||||
{
|
||||
if (CHARDEV_IS_MUX(child)) {
|
||||
/* send OPENED to all already-attached FEs */
|
||||
mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED);
|
||||
/* mark mux as OPENED so any new FEs will immediately receive
|
||||
* OPENED event
|
||||
*/
|
||||
qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED);
|
||||
Chardev *chr = (Chardev *)child;
|
||||
ChardevClass *class = CHARDEV_GET_CLASS(chr);
|
||||
|
||||
if (class->chr_machine_done) {
|
||||
return class->chr_machine_done(chr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void muxes_realize_done(Notifier *notifier, void *unused)
|
||||
static void chardev_machine_done_hook(Notifier *notifier, void *unused)
|
||||
{
|
||||
muxes_realized = true;
|
||||
object_child_foreach(get_chardevs_root(), open_muxes, NULL);
|
||||
int ret = object_child_foreach(get_chardevs_root(),
|
||||
chardev_machine_done_notify_one, NULL);
|
||||
|
||||
if (ret) {
|
||||
error_report("Failed to call chardev machine_done hooks");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static Notifier muxes_realize_notify = {
|
||||
.notify = muxes_realize_done,
|
||||
static Notifier chardev_machine_done_notify = {
|
||||
.notify = chardev_machine_done_hook,
|
||||
};
|
||||
|
||||
static bool qemu_chr_is_busy(Chardev *s)
|
||||
@ -1121,7 +1112,7 @@ static void register_types(void)
|
||||
* as part of realize functions like serial_isa_realizefn when -nographic
|
||||
* is specified
|
||||
*/
|
||||
qemu_add_machine_init_done_notifier(&muxes_realize_notify);
|
||||
qemu_add_machine_init_done_notifier(&chardev_machine_done_notify);
|
||||
}
|
||||
|
||||
type_init(register_types);
|
||||
|
44
configure
vendored
44
configure
vendored
@ -342,7 +342,7 @@ attr=""
|
||||
libattr=""
|
||||
xfs=""
|
||||
tcg="yes"
|
||||
|
||||
membarrier=""
|
||||
vhost_net="no"
|
||||
vhost_crypto="no"
|
||||
vhost_scsi="no"
|
||||
@ -1161,9 +1161,13 @@ for opt do
|
||||
;;
|
||||
--enable-attr) attr="yes"
|
||||
;;
|
||||
--disable-membarrier) membarrier="no"
|
||||
;;
|
||||
--enable-membarrier) membarrier="yes"
|
||||
;;
|
||||
--disable-blobs) blobs="no"
|
||||
;;
|
||||
--with-pkgversion=*) pkgversion=" ($optarg)"
|
||||
--with-pkgversion=*) pkgversion="$optarg"
|
||||
;;
|
||||
--with-coroutine=*) coroutine="$optarg"
|
||||
;;
|
||||
@ -1577,6 +1581,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
xen-pci-passthrough
|
||||
brlapi BrlAPI (Braile)
|
||||
curl curl connectivity
|
||||
membarrier membarrier system call (for Linux 4.14+ or Windows)
|
||||
fdt fdt device tree
|
||||
bluez bluez stack connectivity
|
||||
kvm KVM acceleration support
|
||||
@ -5138,6 +5143,37 @@ if compile_prog "" "" ; then
|
||||
have_fsxattr=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check for usable membarrier system call
|
||||
if test "$membarrier" = "yes"; then
|
||||
have_membarrier=no
|
||||
if test "$mingw32" = "yes" ; then
|
||||
have_membarrier=yes
|
||||
elif test "$linux" = "yes" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <linux/membarrier.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
int main(void) {
|
||||
syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
|
||||
syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0);
|
||||
exit(0);
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
have_membarrier=yes
|
||||
fi
|
||||
fi
|
||||
if test "$have_membarrier" = "no"; then
|
||||
feature_not_found "membarrier" "membarrier system call not available"
|
||||
fi
|
||||
else
|
||||
# Do not enable it by default even for Mingw32, because it doesn't
|
||||
# work on Wine.
|
||||
membarrier=no
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check if rtnetlink.h exists and is useful
|
||||
have_rtnetlink=no
|
||||
@ -5764,6 +5800,7 @@ fi
|
||||
echo "malloc trim support $malloc_trim"
|
||||
echo "RDMA support $rdma"
|
||||
echo "fdt support $fdt"
|
||||
echo "membarrier $membarrier"
|
||||
echo "preadv support $preadv"
|
||||
echo "fdatasync $fdatasync"
|
||||
echo "madvise $madvise"
|
||||
@ -6251,6 +6288,9 @@ fi
|
||||
if test "$fdt" = "yes" ; then
|
||||
echo "CONFIG_FDT=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$membarrier" = "yes" ; then
|
||||
echo "CONFIG_MEMBARRIER=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$signalfd" = "yes" ; then
|
||||
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
|
||||
fi
|
||||
|
24
cpus.c
24
cpus.c
@ -1317,6 +1317,8 @@ static void prepare_icount_for_run(CPUState *cpu)
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
cpu->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
|
||||
replay_mutex_lock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1332,6 +1334,8 @@ static void process_icount_data(CPUState *cpu)
|
||||
cpu->icount_budget = 0;
|
||||
|
||||
replay_account_executed_instructions();
|
||||
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1346,11 +1350,9 @@ static int tcg_cpu_exec(CPUState *cpu)
|
||||
#ifdef CONFIG_PROFILER
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu_exec_start(cpu);
|
||||
ret = cpu_exec(cpu);
|
||||
cpu_exec_end(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
#ifdef CONFIG_PROFILER
|
||||
tcg_time += profile_getclock() - ti;
|
||||
#endif
|
||||
@ -1417,6 +1419,9 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
|
||||
cpu->exit_request = 1;
|
||||
|
||||
while (1) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
replay_mutex_lock();
|
||||
qemu_mutex_lock_iothread();
|
||||
/* Account partial waits to QEMU_CLOCK_VIRTUAL. */
|
||||
qemu_account_warp_timer();
|
||||
|
||||
@ -1425,6 +1430,8 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
|
||||
*/
|
||||
handle_icount_deadline();
|
||||
|
||||
replay_mutex_unlock();
|
||||
|
||||
if (!cpu) {
|
||||
cpu = first_cpu;
|
||||
}
|
||||
@ -1440,11 +1447,13 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
|
||||
if (cpu_can_run(cpu)) {
|
||||
int r;
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
prepare_icount_for_run(cpu);
|
||||
|
||||
r = tcg_cpu_exec(cpu);
|
||||
|
||||
process_icount_data(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(cpu);
|
||||
@ -1634,7 +1643,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
while (1) {
|
||||
if (cpu_can_run(cpu)) {
|
||||
int r;
|
||||
qemu_mutex_unlock_iothread();
|
||||
r = tcg_cpu_exec(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
switch (r) {
|
||||
case EXCP_DEBUG:
|
||||
cpu_handle_guest_debug(cpu);
|
||||
@ -1781,12 +1792,21 @@ void pause_all_vcpus(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to drop the replay_lock so any vCPU threads woken up
|
||||
* can finish their replay tasks
|
||||
*/
|
||||
replay_mutex_unlock();
|
||||
|
||||
while (!all_vcpus_paused()) {
|
||||
qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
|
||||
CPU_FOREACH(cpu) {
|
||||
qemu_cpu_kick(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
replay_mutex_lock();
|
||||
qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
void cpu_resume(CPUState *cpu)
|
||||
|
@ -4,7 +4,12 @@ include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_I82374=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_PARALLEL_ISA=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_IDE_CORE=y
|
||||
|
@ -64,3 +64,5 @@ CONFIG_ACPI_VMGENID=y
|
||||
CONFIG_FW_CFG_DMA=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_SEV=$(CONFIG_KVM)
|
||||
CONFIG_VTD=y
|
||||
CONFIG_AMD_IOMMU=y
|
||||
|
@ -64,3 +64,5 @@ CONFIG_ACPI_VMGENID=y
|
||||
CONFIG_FW_CFG_DMA=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_SEV=$(CONFIG_KVM)
|
||||
CONFIG_VTD=y
|
||||
CONFIG_AMD_IOMMU=y
|
||||
|
@ -122,20 +122,30 @@ In general, if the algorithm you are writing includes both writes
|
||||
and reads on the same side, it is generally simpler to use sequentially
|
||||
consistent primitives.
|
||||
|
||||
When using this model, variables are accessed with atomic_read() and
|
||||
atomic_set(), and restrictions to the ordering of accesses is enforced
|
||||
When using this model, variables are accessed with:
|
||||
|
||||
- atomic_read() and atomic_set(); these prevent the compiler from
|
||||
optimizing accesses out of existence and creating unsolicited
|
||||
accesses, but do not otherwise impose any ordering on loads and
|
||||
stores: both the compiler and the processor are free to reorder
|
||||
them.
|
||||
|
||||
- atomic_load_acquire(), which guarantees the LOAD to appear to
|
||||
happen, with respect to the other components of the system,
|
||||
before all the LOAD or STORE operations specified afterwards.
|
||||
Operations coming before atomic_load_acquire() can still be
|
||||
reordered after it.
|
||||
|
||||
- atomic_store_release(), which guarantees the STORE to appear to
|
||||
happen, with respect to the other components of the system,
|
||||
after all the LOAD or STORE operations specified afterwards.
|
||||
Operations coming after atomic_store_release() can still be
|
||||
reordered after it.
|
||||
|
||||
Restrictions to the ordering of accesses can also be specified
|
||||
using the memory barrier macros: smp_rmb(), smp_wmb(), smp_mb(),
|
||||
smp_mb_acquire(), smp_mb_release(), smp_read_barrier_depends().
|
||||
|
||||
atomic_read() and atomic_set() prevents the compiler from using
|
||||
optimizations that might otherwise optimize accesses out of existence
|
||||
on the one hand, or that might create unsolicited accesses on the other.
|
||||
In general this should not have any effect, because the same compiler
|
||||
barriers are already implied by memory barriers. However, it is useful
|
||||
to do so, because it tells readers which variables are shared with
|
||||
other threads, and which are local to the current thread or protected
|
||||
by other, more mundane means.
|
||||
|
||||
Memory barriers control the order of references to shared memory.
|
||||
They come in six kinds:
|
||||
|
||||
@ -232,7 +242,7 @@ make atomic_mb_set() the more expensive operation.
|
||||
|
||||
There are two common cases in which atomic_mb_read and atomic_mb_set
|
||||
generate too many memory barriers, and thus it can be useful to manually
|
||||
place barriers instead:
|
||||
place barriers, or use atomic_load_acquire/atomic_store_release instead:
|
||||
|
||||
- when a data structure has one thread that is always a writer
|
||||
and one thread that is always a reader, manual placement of
|
||||
@ -243,18 +253,15 @@ place barriers instead:
|
||||
thread 1 thread 1
|
||||
------------------------- ------------------------
|
||||
(other writes)
|
||||
smp_mb_release()
|
||||
atomic_mb_set(&a, x) atomic_set(&a, x)
|
||||
smp_wmb()
|
||||
atomic_mb_set(&b, y) atomic_set(&b, y)
|
||||
atomic_mb_set(&a, x) atomic_store_release(&a, x)
|
||||
atomic_mb_set(&b, y) atomic_store_release(&b, y)
|
||||
|
||||
=>
|
||||
thread 2 thread 2
|
||||
------------------------- ------------------------
|
||||
y = atomic_mb_read(&b) y = atomic_read(&b)
|
||||
smp_rmb()
|
||||
x = atomic_mb_read(&a) x = atomic_read(&a)
|
||||
smp_mb_acquire()
|
||||
y = atomic_mb_read(&b) y = atomic_load_acquire(&b)
|
||||
x = atomic_mb_read(&a) x = atomic_load_acquire(&a)
|
||||
(other reads)
|
||||
|
||||
Note that the barrier between the stores in thread 1, and between
|
||||
the loads in thread 2, has been optimized here to a write or a
|
||||
@ -276,7 +283,6 @@ place barriers instead:
|
||||
smp_mb_acquire();
|
||||
|
||||
Similarly, atomic_mb_set() can be transformed as follows:
|
||||
smp_mb():
|
||||
|
||||
smp_mb_release();
|
||||
for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++)
|
||||
@ -284,6 +290,8 @@ place barriers instead:
|
||||
smp_mb();
|
||||
|
||||
|
||||
The other thread can still use atomic_mb_read()/atomic_mb_set().
|
||||
|
||||
The two tricks can be combined. In this case, splitting a loop in
|
||||
two lets you hoist the barriers out of the loops _and_ eliminate the
|
||||
expensive smp_mb():
|
||||
@ -296,8 +304,6 @@ expensive smp_mb():
|
||||
atomic_set(&a[i], false);
|
||||
smp_mb();
|
||||
|
||||
The other thread can still use atomic_mb_read()/atomic_mb_set()
|
||||
|
||||
|
||||
Memory barrier pairing
|
||||
----------------------
|
||||
@ -386,10 +392,7 @@ and memory barriers, and the equivalents in QEMU:
|
||||
note that smp_store_mb() is a little weaker than atomic_mb_set().
|
||||
atomic_mb_read() compiles to the same instructions as Linux's
|
||||
smp_load_acquire(), but this should be treated as an implementation
|
||||
detail. QEMU does have atomic_load_acquire() and atomic_store_release()
|
||||
macros, but for now they are only used within atomic.h. This may
|
||||
change in the future.
|
||||
|
||||
detail.
|
||||
|
||||
SOURCES
|
||||
=======
|
||||
|
161
docs/replay.txt
161
docs/replay.txt
@ -7,14 +7,10 @@ See the COPYING file in the top-level directory.
|
||||
Record/replay
|
||||
-------------
|
||||
|
||||
Record/replay functions are used for the reverse execution and deterministic
|
||||
replay of qemu execution. This implementation of deterministic replay can
|
||||
be used for deterministic debugging of guest code through a gdb remote
|
||||
interface.
|
||||
|
||||
Record/replay functions are used for the deterministic replay of qemu execution.
|
||||
Execution recording writes a non-deterministic events log, which can be later
|
||||
used for replaying the execution anywhere and for unlimited number of times.
|
||||
It also supports checkpointing for faster rewinding during reverse debugging.
|
||||
It also supports checkpointing for faster rewind to the specific replay moment.
|
||||
Execution replaying reads the log and replays all non-deterministic events
|
||||
including external input, hardware clocks, and interrupts.
|
||||
|
||||
@ -28,16 +24,36 @@ Deterministic replay has the following features:
|
||||
input devices.
|
||||
|
||||
Usage of the record/replay:
|
||||
* First, record the execution, by adding the following arguments to the command line:
|
||||
'-icount shift=7,rr=record,rrfile=replay.bin -net none'.
|
||||
Block devices' images are not actually changed in the recording mode,
|
||||
* First, record the execution with the following command line:
|
||||
qemu-system-i386 \
|
||||
-icount shift=7,rr=record,rrfile=replay.bin \
|
||||
-drive file=disk.qcow2,if=none,id=img-direct \
|
||||
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
|
||||
-device ide-hd,drive=img-blkreplay \
|
||||
-netdev user,id=net1 -device rtl8139,netdev=net1 \
|
||||
-object filter-replay,id=replay,netdev=net1
|
||||
* After recording, you can replay it by using another command line:
|
||||
qemu-system-i386 \
|
||||
-icount shift=7,rr=replay,rrfile=replay.bin \
|
||||
-drive file=disk.qcow2,if=none,id=img-direct \
|
||||
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
|
||||
-device ide-hd,drive=img-blkreplay \
|
||||
-netdev user,id=net1 -device rtl8139,netdev=net1 \
|
||||
-object filter-replay,id=replay,netdev=net1
|
||||
The only difference with recording is changing the rr option
|
||||
from record to replay.
|
||||
* Block device images are not actually changed in the recording mode,
|
||||
because all of the changes are written to the temporary overlay file.
|
||||
* Then you can replay it by using another command
|
||||
line option: '-icount shift=7,rr=replay,rrfile=replay.bin -net none'
|
||||
* '-net none' option should also be specified if network replay patches
|
||||
are not applied.
|
||||
This behavior is enabled by using blkreplay driver. It should be used
|
||||
for every enabled block device, as described in 'Block devices' section.
|
||||
* '-net none' option should be specified when network is not used,
|
||||
because QEMU adds network card by default. When network is needed,
|
||||
it should be configured explicitly with replay filter, as described
|
||||
in 'Network devices' section.
|
||||
* Interaction with audio devices and serial ports are recorded and replayed
|
||||
automatically when such devices are enabled.
|
||||
|
||||
Papers with description of deterministic replay implementation:
|
||||
Academic papers with description of deterministic replay implementation:
|
||||
http://www.computer.org/csdl/proceedings/csmr/2012/4666/00/4666a553-abs.html
|
||||
http://dl.acm.org/citation.cfm?id=2786805.2803179
|
||||
|
||||
@ -46,8 +62,33 @@ Modifications of qemu include:
|
||||
* saving different asynchronous events (e.g. system shutdown) into the log
|
||||
* synchronization of the bottom halves execution
|
||||
* synchronization of the threads from thread pool
|
||||
* recording/replaying user input (mouse and keyboard)
|
||||
* recording/replaying user input (mouse, keyboard, and microphone)
|
||||
* adding internal checkpoints for cpu and io synchronization
|
||||
* network filter for recording and replaying the packets
|
||||
* block driver for making block layer deterministic
|
||||
* serial port input record and replay
|
||||
|
||||
Locking and thread synchronisation
|
||||
----------------------------------
|
||||
|
||||
Previously the synchronisation of the main thread and the vCPU thread
|
||||
was ensured by the holding of the BQL. However the trend has been to
|
||||
reduce the time the BQL was held across the system including under TCG
|
||||
system emulation. As it is important that batches of events are kept
|
||||
in sequence (e.g. expiring timers and checkpoints in the main thread
|
||||
while instruction checkpoints are written by the vCPU thread) we need
|
||||
another lock to keep things in lock-step. This role is now handled by
|
||||
the replay_mutex_lock. It used to be held only for each event being
|
||||
written but now it is held for a whole execution period. This results
|
||||
in a deterministic ping-pong between the two main threads.
|
||||
|
||||
As the BQL is now a finer grained lock than the replay_lock it is almost
|
||||
certainly a bug, and a source of deadlocks, to take the
|
||||
replay_mutex_lock while the BQL is held. This is enforced by an assert.
|
||||
While the unlocks are usually in the reverse order, this is not
|
||||
necessary; you can drop the replay_lock while holding the BQL, without
|
||||
doing a more complicated unlock_iothread/replay_unlock/lock_iothread
|
||||
sequence.
|
||||
|
||||
Non-deterministic events
|
||||
------------------------
|
||||
@ -55,12 +96,11 @@ Non-deterministic events
|
||||
Our record/replay system is based on saving and replaying non-deterministic
|
||||
events (e.g. keyboard input) and simulating deterministic ones (e.g. reading
|
||||
from HDD or memory of the VM). Saving only non-deterministic events makes
|
||||
log file smaller, simulation faster, and allows using reverse debugging even
|
||||
for realtime applications.
|
||||
log file smaller and simulation faster.
|
||||
|
||||
The following non-deterministic data from peripheral devices is saved into
|
||||
the log: mouse and keyboard input, network packets, audio controller input,
|
||||
USB packets, serial port input, and hardware clocks (they are non-deterministic
|
||||
serial port input, and hardware clocks (they are non-deterministic
|
||||
too, because their values are taken from the host machine). Inputs from
|
||||
simulated hardware, memory of VM, software interrupts, and execution of
|
||||
instructions are not saved into the log, because they are deterministic and
|
||||
@ -183,7 +223,7 @@ Block devices record/replay module intercepts calls of
|
||||
bdrv coroutine functions at the top of block drivers stack.
|
||||
To record and replay block operations the drive must be configured
|
||||
as following:
|
||||
-drive file=disk.qcow,if=none,id=img-direct
|
||||
-drive file=disk.qcow2,if=none,id=img-direct
|
||||
-drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
|
||||
-device ide-hd,drive=img-blkreplay
|
||||
|
||||
@ -212,6 +252,12 @@ This snapshot is created at start of recording and restored at start
|
||||
of replaying. It also can be loaded while replaying to roll back
|
||||
the execution.
|
||||
|
||||
Use QEMU monitor to create additional snapshots. 'savevm <name>' command
|
||||
created the snapshot and 'loadvm <name>' restores it. To prevent corruption
|
||||
of the original disk image, use overlay files linked to the original images.
|
||||
Therefore all new snapshots (including the starting one) will be saved in
|
||||
overlays and the original image remains unchanged.
|
||||
|
||||
Network devices
|
||||
---------------
|
||||
|
||||
@ -232,3 +278,80 @@ Audio devices
|
||||
Audio data is recorded and replay automatically. The command line for recording
|
||||
and replaying must contain identical specifications of audio hardware, e.g.:
|
||||
-soundhw ac97
|
||||
|
||||
Serial ports
|
||||
------------
|
||||
|
||||
Serial ports input is recorded and replay automatically. The command lines
|
||||
for recording and replaying must contain identical number of ports in record
|
||||
and replay modes, but their backends may differ.
|
||||
E.g., '-serial stdio' in record mode, and '-serial null' in replay mode.
|
||||
|
||||
Replay log format
|
||||
-----------------
|
||||
|
||||
Record/replay log consits of the header and the sequence of execution
|
||||
events. The header includes 4-byte replay version id and 8-byte reserved
|
||||
field. Version is updated every time replay log format changes to prevent
|
||||
using replay log created by another build of qemu.
|
||||
|
||||
The sequence of the events describes virtual machine state changes.
|
||||
It includes all non-deterministic inputs of VM, synchronization marks and
|
||||
instruction counts used to correctly inject inputs at replay.
|
||||
|
||||
Synchronization marks (checkpoints) are used for synchronizing qemu threads
|
||||
that perform operations with virtual hardware. These operations may change
|
||||
system's state (e.g., change some register or generate interrupt) and
|
||||
therefore should execute synchronously with CPU thread.
|
||||
|
||||
Every event in the log includes 1-byte event id and optional arguments.
|
||||
When argument is an array, it is stored as 4-byte array length
|
||||
and corresponding number of bytes with data.
|
||||
Here is the list of events that are written into the log:
|
||||
|
||||
- EVENT_INSTRUCTION. Instructions executed since last event.
|
||||
Argument: 4-byte number of executed instructions.
|
||||
- EVENT_INTERRUPT. Used to synchronize interrupt processing.
|
||||
- EVENT_EXCEPTION. Used to synchronize exception handling.
|
||||
- EVENT_ASYNC. This is a group of events. They are always processed
|
||||
together with checkpoints. When such an event is generated, it is
|
||||
stored in the queue and processed only when checkpoint occurs.
|
||||
Every such event is followed by 1-byte checkpoint id and 1-byte
|
||||
async event id from the following list:
|
||||
- REPLAY_ASYNC_EVENT_BH. Bottom-half callback. This event synchronizes
|
||||
callbacks that affect virtual machine state, but normally called
|
||||
asyncronously.
|
||||
Argument: 8-byte operation id.
|
||||
- REPLAY_ASYNC_EVENT_INPUT. Input device event. Contains
|
||||
parameters of keyboard and mouse input operations
|
||||
(key press/release, mouse pointer movement).
|
||||
Arguments: 9-16 bytes depending of input event.
|
||||
- REPLAY_ASYNC_EVENT_INPUT_SYNC. Internal input synchronization event.
|
||||
- REPLAY_ASYNC_EVENT_CHAR_READ. Character (e.g., serial port) device input
|
||||
initiated by the sender.
|
||||
Arguments: 1-byte character device id.
|
||||
Array with bytes were read.
|
||||
- REPLAY_ASYNC_EVENT_BLOCK. Block device operation. Used to synchronize
|
||||
operations with disk and flash drives with CPU.
|
||||
Argument: 8-byte operation id.
|
||||
- REPLAY_ASYNC_EVENT_NET. Incoming network packet.
|
||||
Arguments: 1-byte network adapter id.
|
||||
4-byte packet flags.
|
||||
Array with packet bytes.
|
||||
- EVENT_SHUTDOWN. Occurs when user sends shutdown event to qemu,
|
||||
e.g., by closing the window.
|
||||
- EVENT_CHAR_WRITE. Used to synchronize character output operations.
|
||||
Arguments: 4-byte output function return value.
|
||||
4-byte offset in the output array.
|
||||
- EVENT_CHAR_READ_ALL. Used to synchronize character input operations,
|
||||
initiated by qemu.
|
||||
Argument: Array with bytes that were read.
|
||||
- EVENT_CHAR_READ_ALL_ERROR. Unsuccessful character input operation,
|
||||
initiated by qemu.
|
||||
Argument: 4-byte error code.
|
||||
- EVENT_CLOCK + clock_id. Group of events for host clock read operations.
|
||||
Argument: 8-byte clock value.
|
||||
- EVENT_CHECKPOINT + checkpoint_id. Checkpoint for synchronization of
|
||||
CPU, internal threads, and asynchronous input events. May be followed
|
||||
by one or more EVENT_ASYNC events.
|
||||
- EVENT_END. Last event in the log.
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include "hw/timer/mc146818rtc.h"
|
||||
#include "hw/ide.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/isa/superio.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#define MAX_IDE_BUS 2
|
||||
@ -81,19 +82,21 @@ static void clipper_init(MachineState *machine)
|
||||
mc146818_rtc_init(isa_bus, 1900, rtc_irq);
|
||||
|
||||
i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
isa_create_simple(isa_bus, "i8042");
|
||||
|
||||
/* VGA setup. Don't bother loading the bios. */
|
||||
pci_vga_init(pci_bus);
|
||||
|
||||
/* Serial code setup. */
|
||||
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
|
||||
|
||||
/* Network setup. e1000 is good enough, failing Tulip support. */
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
|
||||
}
|
||||
|
||||
/* 2 82C37 (dma) */
|
||||
isa_create_simple(isa_bus, "i82374");
|
||||
|
||||
/* Super I/O */
|
||||
isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
|
||||
|
||||
/* IDE disk setup. */
|
||||
{
|
||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/char/pl011.h"
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/arm/msf2-soc.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/char/pl011.h"
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@ -1,6 +1,7 @@
|
||||
common-obj-$(CONFIG_IPACK) += ipoctal232.o
|
||||
common-obj-$(CONFIG_ESCC) += escc.o
|
||||
common-obj-$(CONFIG_PARALLEL) += parallel.o
|
||||
common-obj-$(CONFIG_PARALLEL) += parallel-isa.o
|
||||
common-obj-$(CONFIG_PL011) += pl011.o
|
||||
common-obj-$(CONFIG_SERIAL) += serial.o
|
||||
common-obj-$(CONFIG_SERIAL_ISA) += serial-isa.o
|
||||
|
36
hw/char/parallel-isa.c
Normal file
36
hw/char/parallel-isa.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* QEMU Parallel PORT (ISA bus helpers)
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/char/parallel.h"
|
||||
|
||||
static void parallel_init(ISABus *bus, int index, Chardev *chr)
|
||||
{
|
||||
DeviceState *dev;
|
||||
ISADevice *isadev;
|
||||
|
||||
isadev = isa_create(bus, "isa-parallel");
|
||||
dev = DEVICE(isadev);
|
||||
qdev_prop_set_uint32(dev, "index", index);
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
|
||||
void parallel_hds_isa_init(ISABus *bus, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(n <= MAX_PARALLEL_PORTS);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (parallel_hds[i]) {
|
||||
parallel_init(bus, i, parallel_hds[i]);
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
#include "chardev/char-parallel.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/char/parallel.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
//#define DEBUG_PARALLEL
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
|
||||
#define TYPE_I82374 "i82374"
|
||||
#define I82374(obj) OBJECT_CHECK(I82374State, (obj), TYPE_I82374)
|
||||
@ -123,7 +124,7 @@ static void i82374_realize(DeviceState *dev, Error **errp)
|
||||
portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj),
|
||||
s->iobase);
|
||||
|
||||
DMA_init(isa_bus_from_device(ISA_DEVICE(dev)), 1);
|
||||
i8257_dma_init(isa_bus_from_device(ISA_DEVICE(dev)), true);
|
||||
memset(s->commands, 0, sizeof(s->commands));
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/isa/i8257.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "trace.h"
|
||||
|
||||
@ -622,7 +622,7 @@ static void i8257_register_types(void)
|
||||
|
||||
type_init(i8257_register_types)
|
||||
|
||||
void DMA_init(ISABus *bus, int high_page_enable)
|
||||
void i8257_dma_init(ISABus *bus, bool high_page_enable)
|
||||
{
|
||||
ISADevice *isa1, *isa2;
|
||||
DeviceState *d;
|
||||
|
@ -2,8 +2,8 @@ obj-$(CONFIG_KVM) += kvm/
|
||||
obj-y += multiboot.o
|
||||
obj-y += pc.o pc_piix.o pc_q35.o
|
||||
obj-y += pc_sysfw.o
|
||||
obj-y += x86-iommu.o intel_iommu.o
|
||||
obj-y += amd_iommu.o
|
||||
obj-$(CONFIG_VTD) += x86-iommu.o intel_iommu.o
|
||||
obj-$(CONFIG_AMD_IOMMU) += x86-iommu.o amd_iommu.o
|
||||
obj-$(CONFIG_XEN) += ../xenpv/ xen/
|
||||
obj-$(CONFIG_VMPORT) += vmport.o
|
||||
obj-$(CONFIG_VMMOUSE) += vmmouse.o
|
||||
|
86
hw/i386/pc.c
86
hw/i386/pc.c
@ -26,6 +26,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/char/parallel.h"
|
||||
#include "hw/i386/apic.h"
|
||||
#include "hw/i386/topology.h"
|
||||
#include "sysemu/cpus.h"
|
||||
@ -40,7 +41,9 @@
|
||||
#include "elf.h"
|
||||
#include "multiboot.h"
|
||||
#include "hw/timer/mc146818rtc.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/audio/pcspk.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/sysbus.h"
|
||||
@ -50,8 +53,6 @@
|
||||
#include "sysemu/qtest.h"
|
||||
#include "kvm_i386.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
@ -1516,6 +1517,44 @@ static const MemoryRegionOps ioportF0_io_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport)
|
||||
{
|
||||
int i;
|
||||
DriveInfo *fd[MAX_FD];
|
||||
qemu_irq *a20_line;
|
||||
ISADevice *i8042, *port92, *vmmouse;
|
||||
|
||||
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
|
||||
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
|
||||
|
||||
for (i = 0; i < MAX_FD; i++) {
|
||||
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
||||
create_fdctrl |= !!fd[i];
|
||||
}
|
||||
if (create_fdctrl) {
|
||||
fdctrl_init_isa(isa_bus, fd);
|
||||
}
|
||||
|
||||
i8042 = isa_create_simple(isa_bus, "i8042");
|
||||
if (!no_vmport) {
|
||||
vmport_init(isa_bus);
|
||||
vmmouse = isa_try_create(isa_bus, "vmmouse");
|
||||
} else {
|
||||
vmmouse = NULL;
|
||||
}
|
||||
if (vmmouse) {
|
||||
DeviceState *dev = DEVICE(vmmouse);
|
||||
qdev_prop_set_ptr(dev, "ps2_mouse", i8042);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
port92 = isa_create_simple(isa_bus, "port92");
|
||||
|
||||
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
|
||||
i8042_setup_a20_line(i8042, a20_line[0]);
|
||||
port92_init(port92, a20_line[1]);
|
||||
g_free(a20_line);
|
||||
}
|
||||
|
||||
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
ISADevice **rtc_state,
|
||||
bool create_fdctrl,
|
||||
@ -1524,13 +1563,11 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
uint32_t hpet_irqs)
|
||||
{
|
||||
int i;
|
||||
DriveInfo *fd[MAX_FD];
|
||||
DeviceState *hpet = NULL;
|
||||
int pit_isa_irq = 0;
|
||||
qemu_irq pit_alt_irq = NULL;
|
||||
qemu_irq rtc_irq = NULL;
|
||||
qemu_irq *a20_line;
|
||||
ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
|
||||
ISADevice *pit = NULL;
|
||||
MemoryRegion *ioport80_io = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1);
|
||||
|
||||
@ -1587,50 +1624,25 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
pcspk_init(isa_bus, pit);
|
||||
}
|
||||
|
||||
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
|
||||
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
|
||||
i8257_dma_init(isa_bus, 0);
|
||||
|
||||
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
|
||||
i8042 = isa_create_simple(isa_bus, "i8042");
|
||||
i8042_setup_a20_line(i8042, a20_line[0]);
|
||||
if (!no_vmport) {
|
||||
vmport_init(isa_bus);
|
||||
vmmouse = isa_try_create(isa_bus, "vmmouse");
|
||||
} else {
|
||||
vmmouse = NULL;
|
||||
}
|
||||
if (vmmouse) {
|
||||
DeviceState *dev = DEVICE(vmmouse);
|
||||
qdev_prop_set_ptr(dev, "ps2_mouse", i8042);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
port92 = isa_create_simple(isa_bus, "port92");
|
||||
port92_init(port92, a20_line[1]);
|
||||
g_free(a20_line);
|
||||
|
||||
DMA_init(isa_bus, 0);
|
||||
|
||||
for(i = 0; i < MAX_FD; i++) {
|
||||
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
||||
create_fdctrl |= !!fd[i];
|
||||
}
|
||||
if (create_fdctrl) {
|
||||
fdctrl_init_isa(isa_bus, fd);
|
||||
}
|
||||
/* Super I/O */
|
||||
pc_superio_init(isa_bus, create_fdctrl, no_vmport);
|
||||
}
|
||||
|
||||
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
|
||||
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC);
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
const char *model = nd->model ? nd->model : pcmc->default_nic_model;
|
||||
|
||||
if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
|
||||
if (g_str_equal(model, "ne2k_isa")) {
|
||||
pc_init_ne2k_isa(isa_bus, nd);
|
||||
} else {
|
||||
pci_nic_init_nofail(nd, pci_bus, "e1000", NULL);
|
||||
pci_nic_init_nofail(nd, pci_bus, model, NULL);
|
||||
}
|
||||
}
|
||||
rom_reset_order_override();
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/i2c/smbus.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "exec/memory.h"
|
||||
@ -240,7 +239,7 @@ static void pc_init1(MachineState *machine,
|
||||
pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true,
|
||||
(pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4);
|
||||
|
||||
pc_nic_init(isa_bus, pci_bus);
|
||||
pc_nic_init(pcmc, isa_bus, pci_bus);
|
||||
|
||||
ide_drive_get(hd, ARRAY_SIZE(hd));
|
||||
if (pcmc->pci_enabled) {
|
||||
@ -417,6 +416,9 @@ static void pc_xen_hvm_init(MachineState *machine)
|
||||
|
||||
static void pc_i440fx_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pcmc->default_nic_model = "e1000";
|
||||
|
||||
m->family = "pc_piix";
|
||||
m->desc = "Standard PC (i440FX + PIIX, 1996)";
|
||||
m->default_machine_opts = "firmware=bios-256k.bin";
|
||||
@ -1114,6 +1116,7 @@ static void isapc_machine_options(MachineClass *m)
|
||||
pcmc->gigabyte_align = false;
|
||||
pcmc->smbios_legacy_mode = true;
|
||||
pcmc->has_reserved_memory = false;
|
||||
pcmc->default_nic_model = "ne2k_isa";
|
||||
m->default_cpu_type = X86_CPU_TYPE_NAME("486");
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ static void pc_q35_init(MachineState *machine)
|
||||
|
||||
/* the rest devices to which pci devfn is automatically assigned */
|
||||
pc_vga_init(isa_bus, host_bus);
|
||||
pc_nic_init(isa_bus, host_bus);
|
||||
pc_nic_init(pcmc, isa_bus, host_bus);
|
||||
|
||||
if (pcms->acpi_nvdimm_state.is_enabled) {
|
||||
nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
|
||||
@ -294,6 +294,9 @@ static void pc_q35_init(MachineState *machine)
|
||||
|
||||
static void pc_q35_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pcmc->default_nic_model = "e1000e";
|
||||
|
||||
m->family = "pc_q35";
|
||||
m->desc = "Standard PC (Q35 + ICH9, 2009)";
|
||||
m->units_per_default_bus = 1;
|
||||
@ -316,7 +319,10 @@ DEFINE_Q35_MACHINE(v2_12, "pc-q35-2.12", NULL,
|
||||
|
||||
static void pc_q35_2_11_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
|
||||
pc_q35_2_12_machine_options(m);
|
||||
pcmc->default_nic_model = "e1000";
|
||||
m->alias = NULL;
|
||||
SET_MACHINE_COMPAT(m, PC_COMPAT_2_11);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/qdev.h"
|
||||
|
||||
/* debug only vmmouse */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "qemu/log.h"
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/ide/internal.h"
|
||||
#include "hw/ide/ahci_internal.h"
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
|
@ -65,7 +65,6 @@
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/ide/ahci_internal.h"
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
#include "hw/ide/internal.h"
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pcmcia.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
#include "hw/ide/internal.h"
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
#include "hw/ide/internal.h"
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/input/ps2.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
/* debug PC keyboard */
|
||||
@ -480,7 +481,6 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
|
||||
qemu_register_reset(kbd_reset, s);
|
||||
}
|
||||
|
||||
#define TYPE_I8042 "i8042"
|
||||
#define I8042(obj) OBJECT_CHECK(ISAKBDState, (obj), TYPE_I8042)
|
||||
|
||||
typedef struct ISAKBDState {
|
||||
|
@ -1,4 +1,5 @@
|
||||
common-obj-$(CONFIG_ISA_BUS) += isa-bus.o
|
||||
common-obj-$(CONFIG_ISA_BUS) += isa-superio.o smc37c669-superio.o
|
||||
common-obj-$(CONFIG_APM) += apm.o
|
||||
common-obj-$(CONFIG_I82378) += i82378.o
|
||||
common-obj-$(CONFIG_PC87312) += pc87312.o
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/i386/pc.h"
|
||||
|
||||
static ISABus *isabus;
|
||||
|
||||
@ -288,28 +287,3 @@ MemoryRegion *isa_address_space_io(ISADevice *dev)
|
||||
}
|
||||
|
||||
type_init(isabus_register_types)
|
||||
|
||||
static void parallel_init(ISABus *bus, int index, Chardev *chr)
|
||||
{
|
||||
DeviceState *dev;
|
||||
ISADevice *isadev;
|
||||
|
||||
isadev = isa_create(bus, "isa-parallel");
|
||||
dev = DEVICE(isadev);
|
||||
qdev_prop_set_uint32(dev, "index", index);
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
|
||||
void parallel_hds_isa_init(ISABus *bus, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(n <= MAX_PARALLEL_PORTS);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (parallel_hds[i]) {
|
||||
parallel_init(bus, i, parallel_hds[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
214
hw/isa/isa-superio.c
Normal file
214
hw/isa/isa-superio.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Generic ISA Super I/O
|
||||
*
|
||||
* Copyright (c) 2010-2012 Herve Poussineau
|
||||
* Copyright (c) 2011-2012 Andreas Färber
|
||||
* Copyright (c) 2018 Philippe Mathieu-Daudé
|
||||
*
|
||||
* This code is licensed under the GNU GPLv2 and later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "chardev/char.h"
|
||||
#include "hw/isa/superio.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "trace.h"
|
||||
|
||||
static void isa_superio_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ISASuperIODevice *sio = ISA_SUPERIO(dev);
|
||||
ISASuperIOClass *k = ISA_SUPERIO_GET_CLASS(sio);
|
||||
ISABus *bus = isa_bus_from_device(ISA_DEVICE(dev));
|
||||
ISADevice *isa;
|
||||
DeviceState *d;
|
||||
Chardev *chr;
|
||||
DriveInfo *drive;
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
/* Parallel port */
|
||||
for (i = 0; i < k->parallel.count; i++) {
|
||||
if (i >= ARRAY_SIZE(sio->parallel)) {
|
||||
warn_report("superio: ignoring %td parallel controllers",
|
||||
k->parallel.count - ARRAY_SIZE(sio->parallel));
|
||||
break;
|
||||
}
|
||||
if (!k->parallel.is_enabled || k->parallel.is_enabled(sio, i)) {
|
||||
/* FIXME use a qdev chardev prop instead of parallel_hds[] */
|
||||
chr = parallel_hds[i];
|
||||
if (chr == NULL || chr->be) {
|
||||
name = g_strdup_printf("discarding-parallel%d", i);
|
||||
chr = qemu_chr_new(name, "null");
|
||||
} else {
|
||||
name = g_strdup_printf("parallel%d", i);
|
||||
}
|
||||
isa = isa_create(bus, "isa-parallel");
|
||||
d = DEVICE(isa);
|
||||
qdev_prop_set_uint32(d, "index", i);
|
||||
if (k->parallel.get_iobase) {
|
||||
qdev_prop_set_uint32(d, "iobase",
|
||||
k->parallel.get_iobase(sio, i));
|
||||
}
|
||||
if (k->parallel.get_irq) {
|
||||
qdev_prop_set_uint32(d, "irq", k->parallel.get_irq(sio, i));
|
||||
}
|
||||
qdev_prop_set_chr(d, "chardev", chr);
|
||||
qdev_init_nofail(d);
|
||||
sio->parallel[i] = isa;
|
||||
trace_superio_create_parallel(i,
|
||||
k->parallel.get_iobase ?
|
||||
k->parallel.get_iobase(sio, i) : -1,
|
||||
k->parallel.get_irq ?
|
||||
k->parallel.get_irq(sio, i) : -1);
|
||||
object_property_add_child(OBJECT(dev), name,
|
||||
OBJECT(sio->parallel[i]), NULL);
|
||||
g_free(name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Serial */
|
||||
for (i = 0; i < k->serial.count; i++) {
|
||||
if (i >= ARRAY_SIZE(sio->serial)) {
|
||||
warn_report("superio: ignoring %td serial controllers",
|
||||
k->serial.count - ARRAY_SIZE(sio->serial));
|
||||
break;
|
||||
}
|
||||
if (!k->serial.is_enabled || k->serial.is_enabled(sio, i)) {
|
||||
/* FIXME use a qdev chardev prop instead of serial_hds[] */
|
||||
chr = serial_hds[i];
|
||||
if (chr == NULL || chr->be) {
|
||||
name = g_strdup_printf("discarding-serial%d", i);
|
||||
chr = qemu_chr_new(name, "null");
|
||||
} else {
|
||||
name = g_strdup_printf("serial%d", i);
|
||||
}
|
||||
isa = isa_create(bus, TYPE_ISA_SERIAL);
|
||||
d = DEVICE(isa);
|
||||
qdev_prop_set_uint32(d, "index", i);
|
||||
if (k->serial.get_iobase) {
|
||||
qdev_prop_set_uint32(d, "iobase",
|
||||
k->serial.get_iobase(sio, i));
|
||||
}
|
||||
if (k->serial.get_irq) {
|
||||
qdev_prop_set_uint32(d, "irq", k->serial.get_irq(sio, i));
|
||||
}
|
||||
qdev_prop_set_chr(d, "chardev", chr);
|
||||
qdev_init_nofail(d);
|
||||
sio->serial[i] = isa;
|
||||
trace_superio_create_serial(i,
|
||||
k->serial.get_iobase ?
|
||||
k->serial.get_iobase(sio, i) : -1,
|
||||
k->serial.get_irq ?
|
||||
k->serial.get_irq(sio, i) : -1);
|
||||
object_property_add_child(OBJECT(dev), name,
|
||||
OBJECT(sio->serial[0]), NULL);
|
||||
g_free(name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Floppy disc */
|
||||
if (!k->floppy.is_enabled || k->floppy.is_enabled(sio, 0)) {
|
||||
isa = isa_create(bus, "isa-fdc");
|
||||
d = DEVICE(isa);
|
||||
if (k->floppy.get_iobase) {
|
||||
qdev_prop_set_uint32(d, "iobase", k->floppy.get_iobase(sio, 0));
|
||||
}
|
||||
if (k->floppy.get_irq) {
|
||||
qdev_prop_set_uint32(d, "irq", k->floppy.get_irq(sio, 0));
|
||||
}
|
||||
/* FIXME use a qdev drive property instead of drive_get() */
|
||||
drive = drive_get(IF_FLOPPY, 0, 0);
|
||||
if (drive != NULL) {
|
||||
qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive),
|
||||
&error_fatal);
|
||||
}
|
||||
/* FIXME use a qdev drive property instead of drive_get() */
|
||||
drive = drive_get(IF_FLOPPY, 0, 1);
|
||||
if (drive != NULL) {
|
||||
qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive),
|
||||
&error_fatal);
|
||||
}
|
||||
qdev_init_nofail(d);
|
||||
sio->floppy = isa;
|
||||
trace_superio_create_floppy(0,
|
||||
k->floppy.get_iobase ?
|
||||
k->floppy.get_iobase(sio, 0) : -1,
|
||||
k->floppy.get_irq ?
|
||||
k->floppy.get_irq(sio, 0) : -1);
|
||||
}
|
||||
|
||||
/* Keyboard, mouse */
|
||||
sio->kbc = isa_create_simple(bus, TYPE_I8042);
|
||||
|
||||
/* IDE */
|
||||
if (k->ide.count && (!k->ide.is_enabled || k->ide.is_enabled(sio, 0))) {
|
||||
isa = isa_create(bus, "isa-ide");
|
||||
d = DEVICE(isa);
|
||||
if (k->ide.get_iobase) {
|
||||
qdev_prop_set_uint32(d, "iobase", k->ide.get_iobase(sio, 0));
|
||||
}
|
||||
if (k->ide.get_iobase) {
|
||||
qdev_prop_set_uint32(d, "iobase2", k->ide.get_iobase(sio, 1));
|
||||
}
|
||||
if (k->ide.get_irq) {
|
||||
qdev_prop_set_uint32(d, "irq", k->ide.get_irq(sio, 0));
|
||||
}
|
||||
qdev_init_nofail(d);
|
||||
sio->ide = isa;
|
||||
trace_superio_create_ide(0,
|
||||
k->ide.get_iobase ?
|
||||
k->ide.get_iobase(sio, 0) : -1,
|
||||
k->ide.get_irq ?
|
||||
k->ide.get_irq(sio, 0) : -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void isa_superio_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = isa_superio_realize;
|
||||
/* Reason: Uses parallel_hds[0] in realize(), so it can't be used twice */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo isa_superio_type_info = {
|
||||
.name = TYPE_ISA_SUPERIO,
|
||||
.parent = TYPE_ISA_DEVICE,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(ISASuperIOClass),
|
||||
.class_init = isa_superio_class_init,
|
||||
};
|
||||
|
||||
/* SMS FDC37M817 Super I/O */
|
||||
static void fdc37m81x_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
|
||||
|
||||
sc->serial.count = 2; /* NS16C550A */
|
||||
sc->parallel.count = 1;
|
||||
sc->floppy.count = 1; /* SMSC 82077AA Compatible */
|
||||
sc->ide.count = 0;
|
||||
}
|
||||
|
||||
static const TypeInfo fdc37m81x_type_info = {
|
||||
.name = TYPE_FDC37M81X_SUPERIO,
|
||||
.parent = TYPE_ISA_SUPERIO,
|
||||
.instance_size = sizeof(ISASuperIODevice),
|
||||
.class_init = fdc37m81x_class_init,
|
||||
};
|
||||
|
||||
static void isa_superio_register_types(void)
|
||||
{
|
||||
type_register_static(&isa_superio_type_info);
|
||||
type_register_static(&fdc37m81x_type_info);
|
||||
}
|
||||
|
||||
type_init(isa_superio_register_types)
|
178
hw/isa/pc87312.c
178
hw/isa/pc87312.c
@ -27,10 +27,6 @@
|
||||
#include "hw/isa/pc87312.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "chardev/char.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
@ -64,22 +60,25 @@
|
||||
|
||||
/* Parallel port */
|
||||
|
||||
static inline bool is_parallel_enabled(PC87312State *s)
|
||||
static bool is_parallel_enabled(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return s->regs[REG_FER] & FER_PARALLEL_EN;
|
||||
PC87312State *s = PC87312(sio);
|
||||
return index ? false : s->regs[REG_FER] & FER_PARALLEL_EN;
|
||||
}
|
||||
|
||||
static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
|
||||
static const uint16_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
|
||||
|
||||
static inline uint32_t get_parallel_iobase(PC87312State *s)
|
||||
static uint16_t get_parallel_iobase(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR];
|
||||
}
|
||||
|
||||
static const uint32_t parallel_irq[] = { 5, 7, 5, 0 };
|
||||
static const unsigned int parallel_irq[] = { 5, 7, 5, 0 };
|
||||
|
||||
static inline uint32_t get_parallel_irq(PC87312State *s)
|
||||
static unsigned int get_parallel_irq(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
int idx;
|
||||
idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR);
|
||||
if (idx == 0) {
|
||||
@ -92,13 +91,14 @@ static inline uint32_t get_parallel_irq(PC87312State *s)
|
||||
|
||||
/* UARTs */
|
||||
|
||||
static const uint32_t uart_base[2][4] = {
|
||||
static const uint16_t uart_base[2][4] = {
|
||||
{ 0x3e8, 0x338, 0x2e8, 0x220 },
|
||||
{ 0x2e8, 0x238, 0x2e0, 0x228 }
|
||||
};
|
||||
|
||||
static inline uint32_t get_uart_iobase(PC87312State *s, int i)
|
||||
static uint16_t get_uart_iobase(ISASuperIODevice *sio, uint8_t i)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
int idx;
|
||||
idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
|
||||
if (idx == 0) {
|
||||
@ -110,44 +110,68 @@ static inline uint32_t get_uart_iobase(PC87312State *s, int i)
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t get_uart_irq(PC87312State *s, int i)
|
||||
static unsigned int get_uart_irq(ISASuperIODevice *sio, uint8_t i)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
int idx;
|
||||
idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
|
||||
return (idx & 1) ? 3 : 4;
|
||||
}
|
||||
|
||||
static inline bool is_uart_enabled(PC87312State *s, int i)
|
||||
static bool is_uart_enabled(ISASuperIODevice *sio, uint8_t i)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
return s->regs[REG_FER] & (FER_UART1_EN << i);
|
||||
}
|
||||
|
||||
|
||||
/* Floppy controller */
|
||||
|
||||
static inline bool is_fdc_enabled(PC87312State *s)
|
||||
static bool is_fdc_enabled(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
assert(!index);
|
||||
return s->regs[REG_FER] & FER_FDC_EN;
|
||||
}
|
||||
|
||||
static inline uint32_t get_fdc_iobase(PC87312State *s)
|
||||
static uint16_t get_fdc_iobase(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
assert(!index);
|
||||
return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0;
|
||||
}
|
||||
|
||||
static unsigned int get_fdc_irq(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
assert(!index);
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
||||
/* IDE controller */
|
||||
|
||||
static inline bool is_ide_enabled(PC87312State *s)
|
||||
static bool is_ide_enabled(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
|
||||
return s->regs[REG_FER] & FER_IDE_EN;
|
||||
}
|
||||
|
||||
static inline uint32_t get_ide_iobase(PC87312State *s)
|
||||
static uint16_t get_ide_iobase(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
PC87312State *s = PC87312(sio);
|
||||
|
||||
if (index == 1) {
|
||||
return get_ide_iobase(sio, 0) + 0x206;
|
||||
}
|
||||
return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0;
|
||||
}
|
||||
|
||||
static unsigned int get_ide_irq(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
assert(index == 0);
|
||||
return 14;
|
||||
}
|
||||
|
||||
static void reconfigure_devices(PC87312State *s)
|
||||
{
|
||||
@ -265,90 +289,18 @@ static void pc87312_reset(DeviceState *d)
|
||||
static void pc87312_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PC87312State *s;
|
||||
DeviceState *d;
|
||||
ISADevice *isa;
|
||||
ISABus *bus;
|
||||
Chardev *chr;
|
||||
DriveInfo *drive;
|
||||
char name[5];
|
||||
int i;
|
||||
Error *local_err = NULL;
|
||||
|
||||
s = PC87312(dev);
|
||||
isa = ISA_DEVICE(dev);
|
||||
bus = isa_bus_from_device(isa);
|
||||
isa_register_ioport(isa, &s->io, s->iobase);
|
||||
pc87312_hard_reset(s);
|
||||
|
||||
if (is_parallel_enabled(s)) {
|
||||
/* FIXME use a qdev chardev prop instead of parallel_hds[] */
|
||||
chr = parallel_hds[0];
|
||||
if (chr == NULL) {
|
||||
chr = qemu_chr_new("par0", "null");
|
||||
}
|
||||
isa = isa_create(bus, "isa-parallel");
|
||||
d = DEVICE(isa);
|
||||
qdev_prop_set_uint32(d, "index", 0);
|
||||
qdev_prop_set_uint32(d, "iobase", get_parallel_iobase(s));
|
||||
qdev_prop_set_uint32(d, "irq", get_parallel_irq(s));
|
||||
qdev_prop_set_chr(d, "chardev", chr);
|
||||
qdev_init_nofail(d);
|
||||
s->parallel.dev = isa;
|
||||
trace_pc87312_info_parallel(get_parallel_iobase(s),
|
||||
get_parallel_irq(s));
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (is_uart_enabled(s, i)) {
|
||||
/* FIXME use a qdev chardev prop instead of serial_hds[] */
|
||||
chr = serial_hds[i];
|
||||
if (chr == NULL) {
|
||||
snprintf(name, sizeof(name), "ser%d", i);
|
||||
chr = qemu_chr_new(name, "null");
|
||||
}
|
||||
isa = isa_create(bus, "isa-serial");
|
||||
d = DEVICE(isa);
|
||||
qdev_prop_set_uint32(d, "index", i);
|
||||
qdev_prop_set_uint32(d, "iobase", get_uart_iobase(s, i));
|
||||
qdev_prop_set_uint32(d, "irq", get_uart_irq(s, i));
|
||||
qdev_prop_set_chr(d, "chardev", chr);
|
||||
qdev_init_nofail(d);
|
||||
s->uart[i].dev = isa;
|
||||
trace_pc87312_info_serial(i, get_uart_iobase(s, i),
|
||||
get_uart_irq(s, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_fdc_enabled(s)) {
|
||||
isa = isa_create(bus, "isa-fdc");
|
||||
d = DEVICE(isa);
|
||||
qdev_prop_set_uint32(d, "iobase", get_fdc_iobase(s));
|
||||
qdev_prop_set_uint32(d, "irq", 6);
|
||||
/* FIXME use a qdev drive property instead of drive_get() */
|
||||
drive = drive_get(IF_FLOPPY, 0, 0);
|
||||
if (drive != NULL) {
|
||||
qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive),
|
||||
&error_fatal);
|
||||
}
|
||||
/* FIXME use a qdev drive property instead of drive_get() */
|
||||
drive = drive_get(IF_FLOPPY, 0, 1);
|
||||
if (drive != NULL) {
|
||||
qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive),
|
||||
&error_fatal);
|
||||
}
|
||||
qdev_init_nofail(d);
|
||||
s->fdc.dev = isa;
|
||||
trace_pc87312_info_floppy(get_fdc_iobase(s));
|
||||
}
|
||||
|
||||
if (is_ide_enabled(s)) {
|
||||
isa = isa_create(bus, "isa-ide");
|
||||
d = DEVICE(isa);
|
||||
qdev_prop_set_uint32(d, "iobase", get_ide_iobase(s));
|
||||
qdev_prop_set_uint32(d, "iobase2", get_ide_iobase(s) + 0x206);
|
||||
qdev_prop_set_uint32(d, "irq", 14);
|
||||
qdev_init_nofail(d);
|
||||
s->ide.dev = isa;
|
||||
trace_pc87312_info_ide(get_ide_iobase(s));
|
||||
ISA_SUPERIO_GET_CLASS(dev)->parent_realize(dev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,7 +325,7 @@ static const VMStateDescription vmstate_pc87312 = {
|
||||
};
|
||||
|
||||
static Property pc87312_properties[] = {
|
||||
DEFINE_PROP_UINT32("iobase", PC87312State, iobase, 0x398),
|
||||
DEFINE_PROP_UINT16("iobase", PC87312State, iobase, 0x398),
|
||||
DEFINE_PROP_UINT8("config", PC87312State, config, 1),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
@ -381,21 +333,47 @@ static Property pc87312_properties[] = {
|
||||
static void pc87312_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
|
||||
|
||||
sc->parent_realize = dc->realize;
|
||||
dc->realize = pc87312_realize;
|
||||
dc->reset = pc87312_reset;
|
||||
dc->vmsd = &vmstate_pc87312;
|
||||
dc->props = pc87312_properties;
|
||||
/* Reason: Uses parallel_hds[0] in realize(), so it can't be used twice */
|
||||
dc->user_creatable = false;
|
||||
|
||||
sc->parallel = (ISASuperIOFuncs){
|
||||
.count = 1,
|
||||
.is_enabled = is_parallel_enabled,
|
||||
.get_iobase = get_parallel_iobase,
|
||||
.get_irq = get_parallel_irq,
|
||||
};
|
||||
sc->serial = (ISASuperIOFuncs){
|
||||
.count = 2,
|
||||
.is_enabled = is_uart_enabled,
|
||||
.get_iobase = get_uart_iobase,
|
||||
.get_irq = get_uart_irq,
|
||||
};
|
||||
sc->floppy = (ISASuperIOFuncs){
|
||||
.count = 1,
|
||||
.is_enabled = is_fdc_enabled,
|
||||
.get_iobase = get_fdc_iobase,
|
||||
.get_irq = get_fdc_irq,
|
||||
};
|
||||
sc->ide = (ISASuperIOFuncs){
|
||||
.count = 1,
|
||||
.is_enabled = is_ide_enabled,
|
||||
.get_iobase = get_ide_iobase,
|
||||
.get_irq = get_ide_irq,
|
||||
};
|
||||
}
|
||||
|
||||
static const TypeInfo pc87312_type_info = {
|
||||
.name = TYPE_PC87312,
|
||||
.parent = TYPE_ISA_DEVICE,
|
||||
.name = TYPE_PC87312_SUPERIO,
|
||||
.parent = TYPE_ISA_SUPERIO,
|
||||
.instance_size = sizeof(PC87312State),
|
||||
.instance_init = pc87312_initfn,
|
||||
.class_init = pc87312_class_init,
|
||||
/* FIXME use a qdev drive property instead of drive_get() */
|
||||
};
|
||||
|
||||
static void pc87312_register_types(void)
|
||||
|
115
hw/isa/smc37c669-superio.c
Normal file
115
hw/isa/smc37c669-superio.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* SMC FDC37C669 Super I/O controller
|
||||
*
|
||||
* Copyright (c) 2018 Philippe Mathieu-Daudé
|
||||
*
|
||||
* This code is licensed under the GNU GPLv2 and later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/isa/superio.h"
|
||||
|
||||
/* UARTs (compatible with NS16450 or PC16550) */
|
||||
|
||||
static bool is_serial_enabled(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return index < 2;
|
||||
}
|
||||
|
||||
static uint16_t get_serial_iobase(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return index ? 0x2f8 : 0x3f8;
|
||||
}
|
||||
|
||||
static unsigned int get_serial_irq(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return index ? 3 : 4;
|
||||
}
|
||||
|
||||
/* Parallel port */
|
||||
|
||||
static bool is_parallel_enabled(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return index < 1;
|
||||
}
|
||||
|
||||
static uint16_t get_parallel_iobase(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return 0x3bc;
|
||||
}
|
||||
|
||||
static unsigned int get_parallel_irq(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
static unsigned int get_parallel_dma(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* Diskette controller (Software compatible with the Intel PC8477) */
|
||||
|
||||
static bool is_fdc_enabled(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return index < 1;
|
||||
}
|
||||
|
||||
static uint16_t get_fdc_iobase(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return 0x3f0;
|
||||
}
|
||||
|
||||
static unsigned int get_fdc_irq(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
static unsigned int get_fdc_dma(ISASuperIODevice *sio, uint8_t index)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void smc37c669_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
|
||||
|
||||
sc->parallel = (ISASuperIOFuncs){
|
||||
.count = 1,
|
||||
.is_enabled = is_parallel_enabled,
|
||||
.get_iobase = get_parallel_iobase,
|
||||
.get_irq = get_parallel_irq,
|
||||
.get_dma = get_parallel_dma,
|
||||
};
|
||||
sc->serial = (ISASuperIOFuncs){
|
||||
.count = 2,
|
||||
.is_enabled = is_serial_enabled,
|
||||
.get_iobase = get_serial_iobase,
|
||||
.get_irq = get_serial_irq,
|
||||
};
|
||||
sc->floppy = (ISASuperIOFuncs){
|
||||
.count = 1,
|
||||
.is_enabled = is_fdc_enabled,
|
||||
.get_iobase = get_fdc_iobase,
|
||||
.get_irq = get_fdc_irq,
|
||||
.get_dma = get_fdc_dma,
|
||||
};
|
||||
sc->ide.count = 0;
|
||||
}
|
||||
|
||||
static const TypeInfo smc37c669_type_info = {
|
||||
.name = TYPE_SMC37C669_SUPERIO,
|
||||
.parent = TYPE_ISA_SUPERIO,
|
||||
.instance_size = sizeof(ISASuperIODevice),
|
||||
.class_size = sizeof(ISASuperIOClass),
|
||||
.class_init = smc37c669_class_init,
|
||||
};
|
||||
|
||||
static void smc37c669_register_types(void)
|
||||
{
|
||||
type_register_static(&smc37c669_type_info);
|
||||
}
|
||||
|
||||
type_init(smc37c669_register_types)
|
@ -1,9 +1,11 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# hw/isa/isa-superio.c
|
||||
superio_create_parallel(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u"
|
||||
superio_create_serial(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u"
|
||||
superio_create_floppy(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u"
|
||||
superio_create_ide(int id, uint16_t base, unsigned int irq) "id=%d, base 0x%03x, irq %u"
|
||||
|
||||
# hw/isa/pc87312.c
|
||||
pc87312_io_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x"
|
||||
pc87312_io_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x"
|
||||
pc87312_info_floppy(uint32_t base) "base 0x%x"
|
||||
pc87312_info_ide(uint32_t base) "base 0x%x"
|
||||
pc87312_info_parallel(uint32_t base, uint32_t irq) "base 0x%x, irq %u"
|
||||
pc87312_info_serial(int n, uint32_t base, uint32_t irq) "id=%d, base 0x%x, irq %u"
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "hw/i2c/smbus.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/isa/superio.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/mips/mips.h"
|
||||
#include "hw/isa/apm.h"
|
||||
@ -478,7 +479,7 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp)
|
||||
qemu_register_reset(vt82c686b_reset, d);
|
||||
}
|
||||
|
||||
ISABus *vt82c686b_init(PCIBus *bus, int devfn)
|
||||
ISABus *vt82c686b_isa_init(PCIBus *bus, int devfn)
|
||||
{
|
||||
PCIDevice *d;
|
||||
|
||||
@ -519,11 +520,30 @@ static const TypeInfo via_info = {
|
||||
},
|
||||
};
|
||||
|
||||
static void vt82c686b_superio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
|
||||
|
||||
sc->serial.count = 2;
|
||||
sc->parallel.count = 1;
|
||||
sc->ide.count = 0;
|
||||
sc->floppy.count = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo via_superio_info = {
|
||||
.name = TYPE_VT82C686B_SUPERIO,
|
||||
.parent = TYPE_ISA_SUPERIO,
|
||||
.instance_size = sizeof(ISASuperIODevice),
|
||||
.class_size = sizeof(ISASuperIOClass),
|
||||
.class_init = vt82c686b_superio_class_init,
|
||||
};
|
||||
|
||||
static void vt82c686b_register_types(void)
|
||||
{
|
||||
type_register_static(&via_ac97_info);
|
||||
type_register_static(&via_mc97_info);
|
||||
type_register_static(&via_pm_info);
|
||||
type_register_static(&via_superio_info);
|
||||
type_register_static(&via_info);
|
||||
}
|
||||
|
||||
|
@ -22,17 +22,15 @@
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/block/fdc.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "hw/isa/superio.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/smbus.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/mips/mips.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "audio/audio.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/loader.h"
|
||||
@ -42,7 +40,6 @@
|
||||
#include "hw/isa/vt82c686.h"
|
||||
#include "hw/timer/mc146818rtc.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "qemu/error-report.h"
|
||||
@ -75,8 +72,6 @@
|
||||
#define FULONG2E_ATI_SLOT 6
|
||||
#define FULONG2E_RTL8139_SLOT 7
|
||||
|
||||
static ISADevice *pit;
|
||||
|
||||
static struct _loaderparams {
|
||||
int ram_size;
|
||||
const char *kernel_filename;
|
||||
@ -229,11 +224,40 @@ static const uint8_t eeprom_spd[0x80] = {
|
||||
0x20,0x30,0x20
|
||||
};
|
||||
|
||||
/* Audio support */
|
||||
static void audio_init (PCIBus *pci_bus)
|
||||
static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc,
|
||||
I2CBus **i2c_bus, ISABus **p_isa_bus)
|
||||
{
|
||||
vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
|
||||
vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
|
||||
qemu_irq *i8259;
|
||||
ISABus *isa_bus;
|
||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||
|
||||
isa_bus = vt82c686b_isa_init(pci_bus, PCI_DEVFN(slot, 0));
|
||||
if (!isa_bus) {
|
||||
fprintf(stderr, "vt82c686b_init error\n");
|
||||
exit(1);
|
||||
}
|
||||
*p_isa_bus = isa_bus;
|
||||
/* Interrupt controller */
|
||||
/* The 8259 -> IP5 */
|
||||
i8259 = i8259_init(isa_bus, intc);
|
||||
isa_bus_irqs(isa_bus, i8259);
|
||||
/* init other devices */
|
||||
i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
i8257_dma_init(isa_bus, 0);
|
||||
/* Super I/O */
|
||||
isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO);
|
||||
|
||||
ide_drive_get(hd, ARRAY_SIZE(hd));
|
||||
vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(slot, 1));
|
||||
|
||||
pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci");
|
||||
pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci");
|
||||
|
||||
*i2c_bus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(slot, 4), 0xeee1, NULL);
|
||||
|
||||
/* Audio support */
|
||||
vt82c686b_ac97_init(pci_bus, PCI_DEVFN(slot, 5));
|
||||
vt82c686b_mc97_init(pci_bus, PCI_DEVFN(slot, 6));
|
||||
}
|
||||
|
||||
/* Network support */
|
||||
@ -266,11 +290,9 @@ static void mips_fulong2e_init(MachineState *machine)
|
||||
MemoryRegion *bios = g_new(MemoryRegion, 1);
|
||||
long bios_size;
|
||||
int64_t kernel_entry;
|
||||
qemu_irq *i8259;
|
||||
PCIBus *pci_bus;
|
||||
ISABus *isa_bus;
|
||||
I2CBus *smbus;
|
||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||
MIPSCPU *cpu;
|
||||
CPUMIPSState *env;
|
||||
|
||||
@ -332,46 +354,16 @@ static void mips_fulong2e_init(MachineState *machine)
|
||||
/* North bridge, Bonito --> IP2 */
|
||||
pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
|
||||
|
||||
/* South bridge */
|
||||
ide_drive_get(hd, ARRAY_SIZE(hd));
|
||||
/* South bridge -> IP5 */
|
||||
vt82c686b_southbridge_init(pci_bus, FULONG2E_VIA_SLOT, env->irq[5],
|
||||
&smbus, &isa_bus);
|
||||
|
||||
isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
|
||||
if (!isa_bus) {
|
||||
error_report("vt82c686b_init error");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Interrupt controller */
|
||||
/* The 8259 -> IP5 */
|
||||
i8259 = i8259_init(isa_bus, env->irq[5]);
|
||||
isa_bus_irqs(isa_bus, i8259);
|
||||
|
||||
vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
|
||||
pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2),
|
||||
"vt82c686b-usb-uhci");
|
||||
pci_create_simple(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3),
|
||||
"vt82c686b-usb-uhci");
|
||||
|
||||
smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
|
||||
0xeee1, NULL);
|
||||
/* TODO: Populate SPD eeprom data. */
|
||||
smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
|
||||
|
||||
/* init other devices */
|
||||
pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
DMA_init(isa_bus, 0);
|
||||
|
||||
/* Super I/O */
|
||||
isa_create_simple(isa_bus, "i8042");
|
||||
|
||||
mc146818_rtc_init(isa_bus, 2000, NULL);
|
||||
|
||||
serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
|
||||
parallel_hds_isa_init(isa_bus, 1);
|
||||
|
||||
/* Sound card */
|
||||
audio_init(pci_bus);
|
||||
/* Network card */
|
||||
/* Network card: RTL8139D */
|
||||
network_init(pci_bus);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,9 @@
|
||||
#include "hw/mips/mips.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/char/parallel.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/block/fdc.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@ -41,7 +43,7 @@
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "hw/display/vga.h"
|
||||
#include "hw/audio/pcspk.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/qtest.h"
|
||||
@ -147,6 +149,7 @@ static void mips_jazz_init(MachineState *machine,
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *bios = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *bios2 = g_new(MemoryRegion, 1);
|
||||
ESPState *esp;
|
||||
|
||||
/* init CPUs */
|
||||
cpu = MIPS_CPU(cpu_create(machine->cpu_type));
|
||||
@ -219,7 +222,7 @@ static void mips_jazz_init(MachineState *machine,
|
||||
/* ISA devices */
|
||||
i8259 = i8259_init(isa_bus, env->irq[4]);
|
||||
isa_bus_irqs(isa_bus, i8259);
|
||||
DMA_init(isa_bus, 0);
|
||||
i8257_dma_init(isa_bus, 0);
|
||||
pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
pcspk_init(isa_bus, pit);
|
||||
|
||||
@ -278,9 +281,9 @@ static void mips_jazz_init(MachineState *machine,
|
||||
}
|
||||
|
||||
/* SCSI adapter */
|
||||
esp_init(0x80002000, 0,
|
||||
rc4030_dma_read, rc4030_dma_write, dmas[0],
|
||||
qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable);
|
||||
esp = esp_init(0x80002000, 0, rc4030_dma_read, rc4030_dma_write, dmas[0],
|
||||
qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable);
|
||||
scsi_bus_legacy_handle_cmdline(&esp->bus);
|
||||
|
||||
/* Floppy */
|
||||
for (n = 0; n < MAX_FD; n++) {
|
||||
|
@ -27,12 +27,12 @@
|
||||
#include "cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/isa/superio.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/block/fdc.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/smbus.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/mips/mips.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
@ -1002,10 +1002,8 @@ void mips_malta_init(MachineState *machine)
|
||||
qemu_irq cbus_irq, i8259_irq;
|
||||
int piix4_devfn;
|
||||
I2CBus *smbus;
|
||||
int i;
|
||||
DriveInfo *dinfo;
|
||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||
DriveInfo *fd[MAX_FD];
|
||||
int fl_idx = 0;
|
||||
int fl_sectors = bios_size >> 16;
|
||||
int be;
|
||||
@ -1020,15 +1018,6 @@ void mips_malta_init(MachineState *machine)
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* Make sure the first 3 serial ports are associated with a device. */
|
||||
for(i = 0; i < 3; i++) {
|
||||
if (!serial_hds[i]) {
|
||||
char label[32];
|
||||
snprintf(label, sizeof(label), "serial%d", i);
|
||||
serial_hds[i] = qemu_chr_new(label, "null");
|
||||
}
|
||||
}
|
||||
|
||||
/* create CPU */
|
||||
mips_create_cpu(s, machine->cpu_type, &cbus_irq, &i8259_irq);
|
||||
|
||||
@ -1059,16 +1048,19 @@ void mips_malta_init(MachineState *machine)
|
||||
memory_region_add_subregion(system_memory, 512 << 20, ram_low_postio);
|
||||
}
|
||||
|
||||
/* generate SPD EEPROM data */
|
||||
generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
|
||||
generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
be = 1;
|
||||
#else
|
||||
be = 0;
|
||||
#endif
|
||||
|
||||
/* FPGA */
|
||||
|
||||
/* Make sure the second serial port is associated with a device. */
|
||||
if (!serial_hds[2]) {
|
||||
serial_hds[2] = qemu_chr_new("fpga-uart", "null");
|
||||
}
|
||||
|
||||
/* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
|
||||
malta_fpga_init(system_memory, FPGA_ADDRESS, cbus_irq, serial_hds[2]);
|
||||
|
||||
@ -1205,22 +1197,18 @@ void mips_malta_init(MachineState *machine)
|
||||
pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
|
||||
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
|
||||
isa_get_irq(NULL, 9), NULL, 0, NULL);
|
||||
pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
i8257_dma_init(isa_bus, 0);
|
||||
mc146818_rtc_init(isa_bus, 2000, NULL);
|
||||
|
||||
/* generate SPD EEPROM data */
|
||||
generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
|
||||
generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
|
||||
smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
|
||||
g_free(smbus_eeprom_buf);
|
||||
pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
DMA_init(isa_bus, 0);
|
||||
|
||||
/* Super I/O */
|
||||
isa_create_simple(isa_bus, "i8042");
|
||||
|
||||
mc146818_rtc_init(isa_bus, 2000, NULL);
|
||||
serial_hds_isa_init(isa_bus, 0, 2);
|
||||
parallel_hds_isa_init(isa_bus, 1);
|
||||
|
||||
for(i = 0; i < MAX_FD; i++) {
|
||||
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
||||
}
|
||||
fdctrl_init_isa(isa_bus, fd);
|
||||
/* Super I/O: SMS FDC37M817 */
|
||||
isa_create_simple(isa_bus, TYPE_FDC37M81X_SUPERIO);
|
||||
|
||||
/* Network card */
|
||||
network_init(pci_bus);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "hw/timer/mc146818rtc.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
@ -286,7 +287,7 @@ void mips_r4k_init(MachineState *machine)
|
||||
hd[MAX_IDE_DEVS * i],
|
||||
hd[MAX_IDE_DEVS * i + 1]);
|
||||
|
||||
isa_create_simple(isa_bus, "i8042");
|
||||
isa_create_simple(isa_bus, TYPE_I8042);
|
||||
}
|
||||
|
||||
static void mips_machine_init(MachineClass *mc)
|
||||
|
61
hw/pci/pci.c
61
hw/pci/pci.c
@ -1815,49 +1815,48 @@ PciInfoList *qmp_query_pci(Error **errp)
|
||||
return head;
|
||||
}
|
||||
|
||||
static const char * const pci_nic_models[] = {
|
||||
"ne2k_pci",
|
||||
"i82551",
|
||||
"i82557b",
|
||||
"i82559er",
|
||||
"rtl8139",
|
||||
"e1000",
|
||||
"pcnet",
|
||||
"virtio",
|
||||
"sungem",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char * const pci_nic_names[] = {
|
||||
"ne2k_pci",
|
||||
"i82551",
|
||||
"i82557b",
|
||||
"i82559er",
|
||||
"rtl8139",
|
||||
"e1000",
|
||||
"pcnet",
|
||||
"virtio-net-pci",
|
||||
"sungem",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Initialize a PCI NIC. */
|
||||
PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
||||
const char *default_model,
|
||||
const char *default_devaddr)
|
||||
{
|
||||
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
|
||||
GSList *list;
|
||||
GPtrArray *pci_nic_models;
|
||||
PCIBus *bus;
|
||||
PCIDevice *pci_dev;
|
||||
DeviceState *dev;
|
||||
int devfn;
|
||||
int i;
|
||||
|
||||
if (qemu_show_nic_models(nd->model, pci_nic_models)) {
|
||||
if (nd->model && !strcmp(nd->model, "virtio")) {
|
||||
g_free(nd->model);
|
||||
nd->model = g_strdup("virtio-net-pci");
|
||||
}
|
||||
|
||||
list = object_class_get_list_sorted(TYPE_PCI_DEVICE, false);
|
||||
pci_nic_models = g_ptr_array_new();
|
||||
while (list) {
|
||||
DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data,
|
||||
TYPE_DEVICE);
|
||||
GSList *next;
|
||||
if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) &&
|
||||
dc->user_creatable) {
|
||||
const char *name = object_class_get_name(list->data);
|
||||
g_ptr_array_add(pci_nic_models, (gpointer)name);
|
||||
}
|
||||
next = list->next;
|
||||
g_slist_free_1(list);
|
||||
list = next;
|
||||
}
|
||||
g_ptr_array_add(pci_nic_models, NULL);
|
||||
|
||||
if (qemu_show_nic_models(nd->model, (const char **)pci_nic_models->pdata)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
i = qemu_find_nic_model(nd, pci_nic_models, default_model);
|
||||
i = qemu_find_nic_model(nd, (const char **)pci_nic_models->pdata,
|
||||
default_model);
|
||||
if (i < 0) {
|
||||
exit(1);
|
||||
}
|
||||
@ -1865,15 +1864,15 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
||||
bus = pci_get_bus_devfn(&devfn, rootbus, devaddr);
|
||||
if (!bus) {
|
||||
error_report("Invalid PCI device address %s for device %s",
|
||||
devaddr, pci_nic_names[i]);
|
||||
devaddr, nd->model);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
|
||||
pci_dev = pci_create(bus, devfn, nd->model);
|
||||
dev = &pci_dev->qdev;
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
g_ptr_array_free(pci_nic_models, true);
|
||||
return pci_dev;
|
||||
}
|
||||
|
||||
|
@ -916,7 +916,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||
if (pci_bus) {
|
||||
/* Register network interfaces. */
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio-net-pci", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,6 @@
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "hw/usb.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
|
@ -41,9 +41,9 @@
|
||||
#include "hw/ide.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/timer/mc146818rtc.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/isa/pc87312.h"
|
||||
#include "hw/net/ne2000-isa.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/qtest.h"
|
||||
@ -612,7 +612,7 @@ static void ppc_prep_init(MachineState *machine)
|
||||
isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci), "isa.0"));
|
||||
|
||||
/* Super I/O (parallel + serial ports) */
|
||||
isa = isa_create(isa_bus, TYPE_PC87312);
|
||||
isa = isa_create(isa_bus, TYPE_PC87312_SUPERIO);
|
||||
dev = DEVICE(isa);
|
||||
qdev_prop_set_uint8(dev, "config", 13); /* fdc, ser0, ser1, par0 */
|
||||
qdev_init_nofail(dev);
|
||||
@ -641,7 +641,6 @@ static void ppc_prep_init(MachineState *machine)
|
||||
hd[2 * i],
|
||||
hd[2 * i + 1]);
|
||||
}
|
||||
isa_create_simple(isa_bus, "i8042");
|
||||
|
||||
cpu = POWERPC_CPU(first_cpu);
|
||||
sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET];
|
||||
@ -771,7 +770,7 @@ static void ibm_40p_init(MachineState *machine)
|
||||
|
||||
/* add some more devices */
|
||||
if (defaults_enabled()) {
|
||||
isa_create_simple(isa_bus, "i8042");
|
||||
isa_create_simple(isa_bus, TYPE_I8042);
|
||||
m48t59 = NVRAM(isa_create_simple(isa_bus, "isa-m48t59"));
|
||||
|
||||
dev = DEVICE(isa_create(isa_bus, "cs4231a"));
|
||||
|
@ -618,11 +618,11 @@ static const MemoryRegionOps sysbus_esp_mem_ops = {
|
||||
.valid.accepts = esp_mem_accepts,
|
||||
};
|
||||
|
||||
void esp_init(hwaddr espaddr, int it_shift,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_read,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_write,
|
||||
void *dma_opaque, qemu_irq irq, qemu_irq *reset,
|
||||
qemu_irq *dma_enable)
|
||||
ESPState *esp_init(hwaddr espaddr, int it_shift,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_read,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_write,
|
||||
void *dma_opaque, qemu_irq irq, qemu_irq *reset,
|
||||
qemu_irq *dma_enable)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *s;
|
||||
@ -644,6 +644,8 @@ void esp_init(hwaddr espaddr, int it_shift,
|
||||
sysbus_mmio_map(s, 0, espaddr);
|
||||
*reset = qdev_get_gpio_in(dev, 0);
|
||||
*dma_enable = qdev_get_gpio_in(dev, 1);
|
||||
|
||||
return esp;
|
||||
}
|
||||
|
||||
static const struct SCSIBusInfo esp_scsi_info = {
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
|
@ -944,7 +944,7 @@ static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
break;
|
||||
case WRITE_SAME_10:
|
||||
case WRITE_SAME_16:
|
||||
cmd->xfer = dev->blocksize;
|
||||
cmd->xfer = buf[1] & 1 ? 0 : dev->blocksize;
|
||||
break;
|
||||
case READ_CAPACITY_10:
|
||||
cmd->xfer = 8;
|
||||
|
@ -704,6 +704,21 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||
page_code);
|
||||
return -1;
|
||||
}
|
||||
if (s->qdev.type == TYPE_DISK) {
|
||||
int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk);
|
||||
int max_io_sectors_blk =
|
||||
max_transfer_blk / s->qdev.blocksize;
|
||||
|
||||
max_io_sectors =
|
||||
MIN_NON_ZERO(max_io_sectors_blk, max_io_sectors);
|
||||
|
||||
/* min_io_size and opt_io_size can't be greater than
|
||||
* max_io_sectors */
|
||||
min_io_size =
|
||||
MIN_NON_ZERO(min_io_size, max_io_sectors);
|
||||
opt_io_size =
|
||||
MIN_NON_ZERO(opt_io_size, max_io_sectors);
|
||||
}
|
||||
/* required VPD size with unmap support */
|
||||
buflen = 0x40;
|
||||
memset(outbuf + 4, 0, buflen - 4);
|
||||
@ -1792,7 +1807,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer_is_zero(inbuf, s->qdev.blocksize)) {
|
||||
if ((req->cmd.buf[1] & 0x1) || buffer_is_zero(inbuf, s->qdev.blocksize)) {
|
||||
int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0;
|
||||
|
||||
/* The request is used as the AIO opaque value, so add a ref. */
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sd/sd.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "hw/empty_slot.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
@ -99,10 +98,6 @@ struct sun4m_hwdef {
|
||||
uint8_t nvram_machine_id;
|
||||
};
|
||||
|
||||
void DMA_init(ISABus *bus, int high_page_enable)
|
||||
{
|
||||
}
|
||||
|
||||
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
|
||||
Error **errp)
|
||||
{
|
||||
|
@ -34,7 +34,9 @@
|
||||
#include "hw/pci-host/sabre.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/char/parallel.h"
|
||||
#include "hw/timer/m48t59.h"
|
||||
#include "hw/input/i8042.h"
|
||||
#include "hw/block/fdc.h"
|
||||
#include "net/net.h"
|
||||
#include "qemu/timer.h"
|
||||
@ -89,10 +91,6 @@ typedef struct EbusState {
|
||||
#define TYPE_EBUS "ebus"
|
||||
#define EBUS(obj) OBJECT_CHECK(EbusState, (obj), TYPE_EBUS)
|
||||
|
||||
void DMA_init(ISABus *bus, int high_page_enable)
|
||||
{
|
||||
}
|
||||
|
||||
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
|
||||
Error **errp)
|
||||
{
|
||||
|
@ -28,9 +28,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "elf.h"
|
||||
#include "hw/tricore/tricore.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#undef DEBUG_PUV3
|
||||
#include "hw/unicore32/puv3.h"
|
||||
#include "hw/input/i8042.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x03000000
|
||||
#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include "chardev/char.h"
|
||||
#include "chardev/char-fe.h"
|
||||
|
||||
extern bool muxes_realized;
|
||||
|
||||
#define MAX_MUX 4
|
||||
#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */
|
||||
#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
|
||||
|
@ -248,6 +248,8 @@ typedef struct ChardevClass {
|
||||
void (*chr_set_echo)(Chardev *chr, bool echo);
|
||||
void (*chr_set_fe_open)(Chardev *chr, int fe_open);
|
||||
void (*chr_be_event)(Chardev *s, int event);
|
||||
/* Return 0 if succeeded, 1 if failed */
|
||||
int (*chr_machine_done)(Chardev *chr);
|
||||
} ChardevClass;
|
||||
|
||||
Chardev *qemu_chardev_new(const char *id, const char *typename,
|
||||
|
14
include/hw/char/parallel.h
Normal file
14
include/hw/char/parallel.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef HW_PARALLEL_H
|
||||
#define HW_PARALLEL_H
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "chardev/char.h"
|
||||
|
||||
void parallel_hds_isa_init(ISABus *bus, int n);
|
||||
|
||||
bool parallel_mm_init(MemoryRegion *address_space,
|
||||
hwaddr base, int it_shift, qemu_irq irq,
|
||||
Chardev *chr);
|
||||
|
||||
#endif
|
@ -1,6 +1,10 @@
|
||||
#ifndef HW_I8257_H
|
||||
#define HW_I8257_H
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "exec/ioport.h"
|
||||
|
||||
#define TYPE_I8257 "i8257"
|
||||
|
||||
typedef struct I8257Regs {
|
||||
@ -40,4 +44,6 @@ typedef struct I8257State {
|
||||
PortioList portio_pageh;
|
||||
} I8257State;
|
||||
|
||||
void i8257_dma_init(ISABus *bus, bool high_page_enable);
|
||||
|
||||
#endif
|
@ -114,6 +114,7 @@ struct PCMachineClass {
|
||||
/* Device configuration: */
|
||||
bool pci_enabled;
|
||||
bool kvmclock_enabled;
|
||||
const char *default_nic_model;
|
||||
|
||||
/* Compat options: */
|
||||
|
||||
@ -151,14 +152,6 @@ struct PCMachineClass {
|
||||
#define PC_MACHINE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PCMachineClass, (klass), TYPE_PC_MACHINE)
|
||||
|
||||
/* parallel.c */
|
||||
|
||||
void parallel_hds_isa_init(ISABus *bus, int n);
|
||||
|
||||
bool parallel_mm_init(MemoryRegion *address_space,
|
||||
hwaddr base, int it_shift, qemu_irq irq,
|
||||
Chardev *chr);
|
||||
|
||||
/* i8259.c */
|
||||
|
||||
extern DeviceState *isa_pic;
|
||||
@ -196,15 +189,6 @@ void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque);
|
||||
void vmmouse_get_data(uint32_t *data);
|
||||
void vmmouse_set_data(const uint32_t *data);
|
||||
|
||||
/* pckbd.c */
|
||||
#define I8042_A20_LINE "a20"
|
||||
|
||||
void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
|
||||
MemoryRegion *region, ram_addr_t size,
|
||||
hwaddr mask);
|
||||
void i8042_isa_mouse_fake_event(void *opaque);
|
||||
void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out);
|
||||
|
||||
/* pc.c */
|
||||
extern int fd_bootchk;
|
||||
|
||||
@ -248,7 +232,7 @@ void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd);
|
||||
void pc_cmos_init(PCMachineState *pcms,
|
||||
BusState *ide0, BusState *ide1,
|
||||
ISADevice *s);
|
||||
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus);
|
||||
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus);
|
||||
void pc_pci_device_init(PCIBus *pci_bus);
|
||||
|
||||
typedef void (*cpu_set_smm_t)(int smm, void *arg);
|
||||
|
24
include/hw/input/i8042.h
Normal file
24
include/hw/input/i8042.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* QEMU PS/2 Controller
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef HW_INPUT_I8042_H
|
||||
#define HW_INPUT_I8042_H
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/isa/isa.h"
|
||||
|
||||
#define TYPE_I8042 "i8042"
|
||||
|
||||
#define I8042_A20_LINE "a20"
|
||||
|
||||
void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
|
||||
MemoryRegion *region, ram_addr_t size,
|
||||
hwaddr mask);
|
||||
void i8042_isa_mouse_fake_event(void *opaque);
|
||||
void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out);
|
||||
|
||||
#endif /* HW_INPUT_I8042_H */
|
@ -151,6 +151,4 @@ static inline ISABus *isa_bus_from_device(ISADevice *d)
|
||||
return ISA_BUS(qdev_get_parent_bus(DEVICE(d)));
|
||||
}
|
||||
|
||||
/* i8257.c */
|
||||
void DMA_init(ISABus *bus, int high_page_enable);
|
||||
#endif
|
||||
|
@ -25,30 +25,20 @@
|
||||
#ifndef QEMU_PC87312_H
|
||||
#define QEMU_PC87312_H
|
||||
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/isa/superio.h"
|
||||
|
||||
|
||||
#define TYPE_PC87312 "pc87312"
|
||||
#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312)
|
||||
#define TYPE_PC87312_SUPERIO "pc87312"
|
||||
#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312_SUPERIO)
|
||||
|
||||
typedef struct PC87312State {
|
||||
ISADevice dev;
|
||||
/*< private >*/
|
||||
ISASuperIODevice parent_dev;
|
||||
/*< public >*/
|
||||
|
||||
uint32_t iobase;
|
||||
uint16_t iobase;
|
||||
uint8_t config; /* initial configuration */
|
||||
|
||||
struct {
|
||||
ISADevice *dev;
|
||||
} parallel;
|
||||
|
||||
struct {
|
||||
ISADevice *dev;
|
||||
} uart[2];
|
||||
|
||||
struct {
|
||||
ISADevice *dev;
|
||||
} fdc;
|
||||
|
||||
struct {
|
||||
ISADevice *dev;
|
||||
} ide;
|
||||
|
60
include/hw/isa/superio.h
Normal file
60
include/hw/isa/superio.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Generic ISA Super I/O
|
||||
*
|
||||
* Copyright (c) 2018 Philippe Mathieu-Daudé
|
||||
*
|
||||
* This code is licensed under the GNU GPLv2 and later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#ifndef HW_ISA_SUPERIO_H
|
||||
#define HW_ISA_SUPERIO_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/isa/isa.h"
|
||||
|
||||
#define TYPE_ISA_SUPERIO "isa-superio"
|
||||
#define ISA_SUPERIO(obj) \
|
||||
OBJECT_CHECK(ISASuperIODevice, (obj), TYPE_ISA_SUPERIO)
|
||||
#define ISA_SUPERIO_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(ISASuperIOClass, (obj), TYPE_ISA_SUPERIO)
|
||||
#define ISA_SUPERIO_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(ISASuperIOClass, (klass), TYPE_ISA_SUPERIO)
|
||||
|
||||
typedef struct ISASuperIODevice {
|
||||
/*< private >*/
|
||||
ISADevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
ISADevice *parallel[MAX_PARALLEL_PORTS];
|
||||
ISADevice *serial[MAX_SERIAL_PORTS];
|
||||
ISADevice *floppy;
|
||||
ISADevice *kbc;
|
||||
ISADevice *ide;
|
||||
} ISASuperIODevice;
|
||||
|
||||
typedef struct ISASuperIOFuncs {
|
||||
size_t count;
|
||||
bool (*is_enabled)(ISASuperIODevice *sio, uint8_t index);
|
||||
uint16_t (*get_iobase)(ISASuperIODevice *sio, uint8_t index);
|
||||
unsigned int (*get_irq)(ISASuperIODevice *sio, uint8_t index);
|
||||
unsigned int (*get_dma)(ISASuperIODevice *sio, uint8_t index);
|
||||
} ISASuperIOFuncs;
|
||||
|
||||
typedef struct ISASuperIOClass {
|
||||
/*< private >*/
|
||||
ISADeviceClass parent_class;
|
||||
/*< public >*/
|
||||
DeviceRealize parent_realize;
|
||||
|
||||
ISASuperIOFuncs parallel;
|
||||
ISASuperIOFuncs serial;
|
||||
ISASuperIOFuncs floppy;
|
||||
ISASuperIOFuncs ide;
|
||||
} ISASuperIOClass;
|
||||
|
||||
#define TYPE_FDC37M81X_SUPERIO "fdc37m81x-superio"
|
||||
#define TYPE_SMC37C669_SUPERIO "smc37c669-superio"
|
||||
|
||||
#endif /* HW_ISA_SUPERIO_H */
|
@ -1,8 +1,10 @@
|
||||
#ifndef HW_VT82C686_H
|
||||
#define HW_VT82C686_H
|
||||
|
||||
#define TYPE_VT82C686B_SUPERIO "vt82c686b-superio"
|
||||
|
||||
/* vt82c686.c */
|
||||
ISABus *vt82c686b_init(PCIBus * bus, int devfn);
|
||||
ISABus *vt82c686b_isa_init(PCIBus * bus, int devfn);
|
||||
void vt82c686b_ac97_init(PCIBus *bus, int devfn);
|
||||
void vt82c686b_mc97_init(PCIBus *bus, int devfn);
|
||||
I2CBus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||
|
@ -7,11 +7,6 @@
|
||||
/* esp.c */
|
||||
#define ESP_MAX_DEVS 7
|
||||
typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
|
||||
void esp_init(hwaddr espaddr, int it_shift,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_read,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_write,
|
||||
void *dma_opaque, qemu_irq irq, qemu_irq *reset,
|
||||
qemu_irq *dma_enable);
|
||||
|
||||
#define ESP_REGS 16
|
||||
#define TI_BUFSZ 16
|
||||
@ -136,6 +131,11 @@ typedef struct {
|
||||
#define TCHI_FAS100A 0x4
|
||||
#define TCHI_AM53C974 0x12
|
||||
|
||||
ESPState *esp_init(hwaddr espaddr, int it_shift,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_read,
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_write,
|
||||
void *dma_opaque, qemu_irq irq, qemu_irq *reset,
|
||||
qemu_irq *dma_enable);
|
||||
void esp_dma_enable(ESPState *s, int irq, int level);
|
||||
void esp_request_cancelled(SCSIRequest *req);
|
||||
void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/sys_membarrier.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -79,7 +80,10 @@ static inline void rcu_read_lock(void)
|
||||
}
|
||||
|
||||
ctr = atomic_read(&rcu_gp_ctr);
|
||||
atomic_xchg(&p_rcu_reader->ctr, ctr);
|
||||
atomic_set(&p_rcu_reader->ctr, ctr);
|
||||
|
||||
/* Write p_rcu_reader->ctr before reading RCU-protected pointers. */
|
||||
smp_mb_placeholder();
|
||||
}
|
||||
|
||||
static inline void rcu_read_unlock(void)
|
||||
@ -91,7 +95,15 @@ static inline void rcu_read_unlock(void)
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_xchg(&p_rcu_reader->ctr, 0);
|
||||
/* Ensure that the critical section is seen to precede the
|
||||
* store to p_rcu_reader->ctr. Together with the following
|
||||
* smp_mb_placeholder(), this ensures writes to p_rcu_reader->ctr
|
||||
* are sequentially consistent.
|
||||
*/
|
||||
atomic_store_release(&p_rcu_reader->ctr, 0);
|
||||
|
||||
/* Write p_rcu_reader->ctr before reading p_rcu_reader->waiting. */
|
||||
smp_mb_placeholder();
|
||||
if (unlikely(atomic_read(&p_rcu_reader->waiting))) {
|
||||
atomic_set(&p_rcu_reader->waiting, false);
|
||||
qemu_event_set(&rcu_gp_event);
|
||||
|
27
include/qemu/sys_membarrier.h
Normal file
27
include/qemu/sys_membarrier.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Process-global memory barriers
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef QEMU_SYS_MEMBARRIER_H
|
||||
#define QEMU_SYS_MEMBARRIER_H 1
|
||||
|
||||
#ifdef CONFIG_MEMBARRIER
|
||||
/* Only block reordering at the compiler level in the performance-critical
|
||||
* side. The slow side forces processor-level ordering on all other cores
|
||||
* through a system call.
|
||||
*/
|
||||
extern void smp_mb_global_init(void);
|
||||
extern void smp_mb_global(void);
|
||||
#define smp_mb_placeholder() barrier()
|
||||
#else
|
||||
/* Keep it simple, execute a real memory barrier on both sides. */
|
||||
static inline void smp_mb_global_init(void) {}
|
||||
#define smp_mb_global() smp_mb()
|
||||
#define smp_mb_placeholder() smp_mb()
|
||||
#endif
|
||||
|
||||
#endif
|
@ -251,6 +251,20 @@ bool qemu_clock_run_timers(QEMUClockType type);
|
||||
*/
|
||||
bool qemu_clock_run_all_timers(void);
|
||||
|
||||
/**
|
||||
* qemu_clock_get_last:
|
||||
*
|
||||
* Returns last clock query time.
|
||||
*/
|
||||
uint64_t qemu_clock_get_last(QEMUClockType type);
|
||||
/**
|
||||
* qemu_clock_set_last:
|
||||
*
|
||||
* Sets last clock query time.
|
||||
*/
|
||||
void qemu_clock_set_last(QEMUClockType type, uint64_t last);
|
||||
|
||||
|
||||
/*
|
||||
* QEMUTimerList
|
||||
*/
|
||||
|
@ -913,6 +913,17 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
|
||||
GSList *object_class_get_list(const char *implements_type,
|
||||
bool include_abstract);
|
||||
|
||||
/**
|
||||
* object_class_get_list_sorted:
|
||||
* @implements_type: The type to filter for, including its derivatives.
|
||||
* @include_abstract: Whether to include abstract classes.
|
||||
*
|
||||
* Returns: A singly-linked list of the classes in alphabetical
|
||||
* case-insensitive order.
|
||||
*/
|
||||
GSList *object_class_get_list_sorted(const char *implements_type,
|
||||
bool include_abstract);
|
||||
|
||||
/**
|
||||
* object_ref:
|
||||
* @obj: the object
|
||||
|
@ -48,6 +48,19 @@ extern ReplayMode replay_mode;
|
||||
/* Name of the initial VM snapshot */
|
||||
extern char *replay_snapshot;
|
||||
|
||||
/* Replay locking
|
||||
*
|
||||
* The locks are needed to protect the shared structures and log file
|
||||
* when doing record/replay. They also are the main sync-point between
|
||||
* the main-loop thread and the vCPU thread. This was a role
|
||||
* previously filled by the BQL which has been busy trying to reduce
|
||||
* its impact across the code. This ensures blocks of events stay
|
||||
* sequential and reproducible.
|
||||
*/
|
||||
|
||||
void replay_mutex_lock(void);
|
||||
void replay_mutex_unlock(void);
|
||||
|
||||
/* Replay process control functions */
|
||||
|
||||
/*! Enables recording or saving event log with specified parameters */
|
||||
@ -166,5 +179,8 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size);
|
||||
/*! Called at the start of execution.
|
||||
Loads or saves initial vmstate depending on execution mode. */
|
||||
void replay_vmstate_init(void);
|
||||
/*! Called to ensure that replay state is consistent and VM snapshot
|
||||
can be created */
|
||||
bool replay_can_snapshot(void);
|
||||
|
||||
#endif
|
||||
|
@ -88,6 +88,8 @@ void qemu_system_guest_panicked(GuestPanicInformation *info);
|
||||
void qemu_add_exit_notifier(Notifier *notify);
|
||||
void qemu_remove_exit_notifier(Notifier *notify);
|
||||
|
||||
extern bool machine_init_done;
|
||||
|
||||
void qemu_add_machine_init_done_notifier(Notifier *notify);
|
||||
void qemu_remove_machine_init_done_notifier(Notifier *notify);
|
||||
|
||||
|
@ -4074,7 +4074,7 @@ static void handle_arg_strace(const char *arg)
|
||||
|
||||
static void handle_arg_version(const char *arg)
|
||||
{
|
||||
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
|
||||
printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
|
||||
"\n" QEMU_COPYRIGHT "\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "qemu/cutils.h"
|
||||
#include "io/channel-buffer.h"
|
||||
#include "io/channel-file.h"
|
||||
#include "sysemu/replay.h"
|
||||
|
||||
#ifndef ETH_P_RARP
|
||||
#define ETH_P_RARP 0x8035
|
||||
@ -2197,6 +2198,12 @@ int save_snapshot(const char *name, Error **errp)
|
||||
struct tm tm;
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!replay_can_snapshot()) {
|
||||
error_report("Record/replay does not allow making snapshot "
|
||||
"right now. Try once more later.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!bdrv_all_can_snapshot(&bs)) {
|
||||
error_setg(errp, "Device '%s' is writable but does not support "
|
||||
"snapshots", bdrv_get_device_name(bs));
|
||||
@ -2388,6 +2395,12 @@ int load_snapshot(const char *name, Error **errp)
|
||||
AioContext *aio_context;
|
||||
MigrationIncomingState *mis = migration_incoming_get_current();
|
||||
|
||||
if (!replay_can_snapshot()) {
|
||||
error_report("Record/replay does not allow loading snapshot "
|
||||
"right now. Try once more later.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!bdrv_all_can_snapshot(&bs)) {
|
||||
error_setg(errp,
|
||||
"Device '%s' is writable but does not support snapshots",
|
||||
|
@ -122,12 +122,6 @@ static void qdev_print_devinfo(DeviceClass *dc)
|
||||
error_printf("\n");
|
||||
}
|
||||
|
||||
static gint devinfo_cmp(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return strcasecmp(object_class_get_name((ObjectClass *)a),
|
||||
object_class_get_name((ObjectClass *)b));
|
||||
}
|
||||
|
||||
static void qdev_print_devinfos(bool show_no_user)
|
||||
{
|
||||
static const char *cat_name[DEVICE_CATEGORY_MAX + 1] = {
|
||||
@ -146,8 +140,7 @@ static void qdev_print_devinfos(bool show_no_user)
|
||||
int i;
|
||||
bool cat_printed;
|
||||
|
||||
list = g_slist_sort(object_class_get_list(TYPE_DEVICE, false),
|
||||
devinfo_cmp);
|
||||
list = object_class_get_list_sorted(TYPE_DEVICE, false);
|
||||
|
||||
for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) {
|
||||
cat_printed = false;
|
||||
|
@ -2643,42 +2643,46 @@ combined with ``-vnc tls-creds=tls0'
|
||||
|
||||
@subsection -tftp (since 2.6.0)
|
||||
|
||||
The ``-tftp /some/dir'' argument is replaced by
|
||||
``-netdev user,id=x,tftp=/some/dir'', either accompanied with
|
||||
``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x''
|
||||
The ``-tftp /some/dir'' argument is replaced by either
|
||||
``-netdev user,id=x,tftp=/some/dir '' (for pluggable NICs, accompanied
|
||||
with ``-device ...,netdev=x''), or ``-nic user,tftp=/some/dir''
|
||||
(for embedded NICs). The new syntax allows different settings to be
|
||||
provided per NIC.
|
||||
|
||||
@subsection -bootp (since 2.6.0)
|
||||
|
||||
The ``-bootp /some/file'' argument is replaced by
|
||||
``-netdev user,id=x,bootp=/some/file'', either accompanied with
|
||||
``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x''
|
||||
The ``-bootp /some/file'' argument is replaced by either
|
||||
``-netdev user,id=x,bootp=/some/file '' (for pluggable NICs, accompanied
|
||||
with ``-device ...,netdev=x''), or ``-nic user,bootp=/some/file''
|
||||
(for embedded NICs). The new syntax allows different settings to be
|
||||
provided per NIC.
|
||||
|
||||
@subsection -redir (since 2.6.0)
|
||||
|
||||
The ``-redir [tcp|udp]:hostport:[guestaddr]:guestport'' argument is
|
||||
replaced by ``-netdev
|
||||
user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport'',
|
||||
either accompanied with ``-device ...,netdev=x'' (for pluggable NICs) or
|
||||
``-net nic,netdev=x'' (for embedded NICs). The new syntax allows different
|
||||
settings to be provided per NIC.
|
||||
replaced by either
|
||||
``-netdev user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport''
|
||||
(for pluggable NICs, accompanied with ``-device ...,netdev=x'') or
|
||||
``-nic user,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport''
|
||||
(for embedded NICs). The new syntax allows different settings to be
|
||||
provided per NIC.
|
||||
|
||||
@subsection -smb (since 2.6.0)
|
||||
|
||||
The ``-smb /some/dir'' argument is replaced by
|
||||
``-netdev user,id=x,smb=/some/dir'', either accompanied with
|
||||
``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x''
|
||||
The ``-smb /some/dir'' argument is replaced by either
|
||||
``-netdev user,id=x,smb=/some/dir '' (for pluggable NICs, accompanied
|
||||
with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
|
||||
(for embedded NICs). The new syntax allows different settings to be
|
||||
provided per NIC.
|
||||
|
||||
@subsection -net vlan (since 2.9.0)
|
||||
|
||||
The ``-net vlan=NN'' argument is partially replaced with the
|
||||
new ``-netdev'' argument. The remaining use cases will no
|
||||
longer be directly supported in QEMU.
|
||||
The ``-net vlan=NN'' argument was mostly used to attach separate
|
||||
network backends to different virtual NICs. This is the default
|
||||
behavior for ``-netdev'' and ``-nic''. You can connect multiple
|
||||
``-netdev'' and ``-nic'' devices to the same network using the
|
||||
"hubport" network backend, created with ``-netdev hubport,hubid=NN,...''
|
||||
and ``-nic hubport,hubid=NN''.
|
||||
|
||||
@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
|
||||
|
||||
@ -2728,6 +2732,12 @@ filesystem test suite. Also it requires the CAP_DAC_READ_SEARCH capability,
|
||||
which is not the recommended way to run QEMU. This backend should not be
|
||||
used and it will be removed with no replacement.
|
||||
|
||||
@subsection -no-frame (since 2.12.0)
|
||||
|
||||
The @code{--no-frame} argument works with SDL 1.2 only. The other user
|
||||
interfaces never implemented this in the first place. So this will be
|
||||
removed together with SDL 1.2 support.
|
||||
|
||||
@subsection -rtc-td-hack (since 2.12.0)
|
||||
|
||||
The @code{-rtc-td-hack} option has been replaced by
|
||||
|
@ -46,7 +46,7 @@
|
||||
#include "crypto/init.h"
|
||||
#include "trace/control.h"
|
||||
|
||||
#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION QEMU_PKGVERSION \
|
||||
#define QEMU_IMG_VERSION "qemu-img version " QEMU_FULL_VERSION \
|
||||
"\n" QEMU_COPYRIGHT "\n"
|
||||
|
||||
typedef struct img_cmd_t {
|
||||
|
@ -558,7 +558,7 @@ int main(int argc, char **argv)
|
||||
trace_file = trace_opt_parse(optarg);
|
||||
break;
|
||||
case 'V':
|
||||
printf("%s version " QEMU_VERSION QEMU_PKGVERSION "\n"
|
||||
printf("%s version " QEMU_FULL_VERSION "\n"
|
||||
QEMU_COPYRIGHT "\n", progname);
|
||||
exit(0);
|
||||
case 'h':
|
||||
|
@ -130,7 +130,7 @@ QEMU_HELP_BOTTOM "\n"
|
||||
static void version(const char *name)
|
||||
{
|
||||
printf(
|
||||
"%s " QEMU_VERSION QEMU_PKGVERSION "\n"
|
||||
"%s " QEMU_FULL_VERSION "\n"
|
||||
"Written by Anthony Liguori.\n"
|
||||
"\n"
|
||||
QEMU_COPYRIGHT "\n"
|
||||
|
@ -218,7 +218,7 @@ static void usage(const char *cmd)
|
||||
{
|
||||
printf(
|
||||
"Usage: %s [-m <method> -p <path>] [<options>]\n"
|
||||
"QEMU Guest Agent " QEMU_VERSION QEMU_PKGVERSION "\n"
|
||||
"QEMU Guest Agent " QEMU_FULL_VERSION "\n"
|
||||
QEMU_COPYRIGHT "\n"
|
||||
"\n"
|
||||
" -m, --method transport method: one of unix-listen, virtio-serial,\n"
|
||||
|
13
qom/object.c
13
qom/object.c
@ -891,6 +891,19 @@ GSList *object_class_get_list(const char *implements_type,
|
||||
return list;
|
||||
}
|
||||
|
||||
static gint object_class_cmp(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return strcasecmp(object_class_get_name((ObjectClass *)a),
|
||||
object_class_get_name((ObjectClass *)b));
|
||||
}
|
||||
|
||||
GSList *object_class_get_list_sorted(const char *implements_type,
|
||||
bool include_abstract)
|
||||
{
|
||||
return g_slist_sort(object_class_get_list(implements_type, include_abstract),
|
||||
object_class_cmp);
|
||||
}
|
||||
|
||||
void object_ref(Object *obj)
|
||||
{
|
||||
if (!obj) {
|
||||
|
@ -19,20 +19,17 @@
|
||||
void replay_audio_out(int *played)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_save_instructions();
|
||||
replay_mutex_lock();
|
||||
replay_put_event(EVENT_AUDIO_OUT);
|
||||
replay_put_dword(*played);
|
||||
replay_mutex_unlock();
|
||||
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_account_executed_instructions();
|
||||
replay_mutex_lock();
|
||||
if (replay_next_event_is(EVENT_AUDIO_OUT)) {
|
||||
*played = replay_get_dword();
|
||||
replay_finish_event();
|
||||
replay_mutex_unlock();
|
||||
} else {
|
||||
replay_mutex_unlock();
|
||||
error_report("Missing audio out event in the replay log");
|
||||
abort();
|
||||
}
|
||||
@ -44,8 +41,8 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
|
||||
int pos;
|
||||
uint64_t left, right;
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_save_instructions();
|
||||
replay_mutex_lock();
|
||||
replay_put_event(EVENT_AUDIO_IN);
|
||||
replay_put_dword(*recorded);
|
||||
replay_put_dword(*wpos);
|
||||
@ -55,10 +52,9 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
|
||||
replay_put_qword(left);
|
||||
replay_put_qword(right);
|
||||
}
|
||||
replay_mutex_unlock();
|
||||
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_account_executed_instructions();
|
||||
replay_mutex_lock();
|
||||
if (replay_next_event_is(EVENT_AUDIO_IN)) {
|
||||
*recorded = replay_get_dword();
|
||||
*wpos = replay_get_dword();
|
||||
@ -69,9 +65,7 @@ void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
|
||||
audio_sample_from_uint64(samples, pos, left, right);
|
||||
}
|
||||
replay_finish_event();
|
||||
replay_mutex_unlock();
|
||||
} else {
|
||||
replay_mutex_unlock();
|
||||
error_report("Missing audio in event in the replay log");
|
||||
abort();
|
||||
}
|
||||
|
@ -96,25 +96,24 @@ void *replay_event_char_read_load(void)
|
||||
|
||||
void replay_char_write_event_save(int res, int offset)
|
||||
{
|
||||
g_assert(replay_mutex_locked());
|
||||
|
||||
replay_save_instructions();
|
||||
replay_mutex_lock();
|
||||
replay_put_event(EVENT_CHAR_WRITE);
|
||||
replay_put_dword(res);
|
||||
replay_put_dword(offset);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
void replay_char_write_event_load(int *res, int *offset)
|
||||
{
|
||||
g_assert(replay_mutex_locked());
|
||||
|
||||
replay_account_executed_instructions();
|
||||
replay_mutex_lock();
|
||||
if (replay_next_event_is(EVENT_CHAR_WRITE)) {
|
||||
*res = replay_get_dword();
|
||||
*offset = replay_get_dword();
|
||||
replay_finish_event();
|
||||
replay_mutex_unlock();
|
||||
} else {
|
||||
replay_mutex_unlock();
|
||||
error_report("Missing character write event in the replay log");
|
||||
exit(1);
|
||||
}
|
||||
@ -122,23 +121,21 @@ void replay_char_write_event_load(int *res, int *offset)
|
||||
|
||||
int replay_char_read_all_load(uint8_t *buf)
|
||||
{
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
|
||||
if (replay_next_event_is(EVENT_CHAR_READ_ALL)) {
|
||||
size_t size;
|
||||
int res;
|
||||
replay_get_array(buf, &size);
|
||||
replay_finish_event();
|
||||
replay_mutex_unlock();
|
||||
res = (int)size;
|
||||
assert(res >= 0);
|
||||
return res;
|
||||
} else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) {
|
||||
int res = replay_get_dword();
|
||||
replay_finish_event();
|
||||
replay_mutex_unlock();
|
||||
return res;
|
||||
} else {
|
||||
replay_mutex_unlock();
|
||||
error_report("Missing character read all event in the replay log");
|
||||
exit(1);
|
||||
}
|
||||
@ -146,19 +143,17 @@ int replay_char_read_all_load(uint8_t *buf)
|
||||
|
||||
void replay_char_read_all_save_error(int res)
|
||||
{
|
||||
g_assert(replay_mutex_locked());
|
||||
assert(res < 0);
|
||||
replay_save_instructions();
|
||||
replay_mutex_lock();
|
||||
replay_put_event(EVENT_CHAR_READ_ALL_ERROR);
|
||||
replay_put_dword(res);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
void replay_char_read_all_save_buf(uint8_t *buf, int offset)
|
||||
{
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_save_instructions();
|
||||
replay_mutex_lock();
|
||||
replay_put_event(EVENT_CHAR_READ_ALL);
|
||||
replay_put_array(buf, offset);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
@ -27,10 +27,6 @@ typedef struct Event {
|
||||
} Event;
|
||||
|
||||
static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list);
|
||||
static unsigned int read_event_kind = -1;
|
||||
static uint64_t read_id = -1;
|
||||
static int read_checkpoint = -1;
|
||||
|
||||
static bool events_enabled;
|
||||
|
||||
/* Functions */
|
||||
@ -67,7 +63,9 @@ static void replay_run_event(Event *event)
|
||||
|
||||
void replay_enable_events(void)
|
||||
{
|
||||
events_enabled = true;
|
||||
if (replay_mode != REPLAY_MODE_NONE) {
|
||||
events_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool replay_has_events(void)
|
||||
@ -77,16 +75,14 @@ bool replay_has_events(void)
|
||||
|
||||
void replay_flush_events(void)
|
||||
{
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
|
||||
while (!QTAILQ_EMPTY(&events_list)) {
|
||||
Event *event = QTAILQ_FIRST(&events_list);
|
||||
replay_mutex_unlock();
|
||||
replay_run_event(event);
|
||||
replay_mutex_lock();
|
||||
QTAILQ_REMOVE(&events_list, event, events);
|
||||
g_free(event);
|
||||
}
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
void replay_disable_events(void)
|
||||
@ -100,14 +96,14 @@ void replay_disable_events(void)
|
||||
|
||||
void replay_clear_events(void)
|
||||
{
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
|
||||
while (!QTAILQ_EMPTY(&events_list)) {
|
||||
Event *event = QTAILQ_FIRST(&events_list);
|
||||
QTAILQ_REMOVE(&events_list, event, events);
|
||||
|
||||
g_free(event);
|
||||
}
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
/*! Adds specified async event to the queue */
|
||||
@ -134,14 +130,13 @@ void replay_add_event(ReplayAsyncEventKind event_kind,
|
||||
event->opaque2 = opaque2;
|
||||
event->id = id;
|
||||
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
QTAILQ_INSERT_TAIL(&events_list, event, events);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
void replay_bh_schedule_event(QEMUBH *bh)
|
||||
{
|
||||
if (replay_mode != REPLAY_MODE_NONE && events_enabled) {
|
||||
if (events_enabled) {
|
||||
uint64_t id = replay_get_current_step();
|
||||
replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
|
||||
} else {
|
||||
@ -161,7 +156,7 @@ void replay_add_input_sync_event(void)
|
||||
|
||||
void replay_block_event(QEMUBH *bh, uint64_t id)
|
||||
{
|
||||
if (replay_mode != REPLAY_MODE_NONE && events_enabled) {
|
||||
if (events_enabled) {
|
||||
replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
|
||||
} else {
|
||||
qemu_bh_schedule(bh);
|
||||
@ -205,13 +200,12 @@ static void replay_save_event(Event *event, int checkpoint)
|
||||
/* Called with replay mutex locked */
|
||||
void replay_save_events(int checkpoint)
|
||||
{
|
||||
g_assert(replay_mutex_locked());
|
||||
g_assert(checkpoint != CHECKPOINT_CLOCK_WARP_START);
|
||||
while (!QTAILQ_EMPTY(&events_list)) {
|
||||
Event *event = QTAILQ_FIRST(&events_list);
|
||||
replay_save_event(event, checkpoint);
|
||||
|
||||
replay_mutex_unlock();
|
||||
replay_run_event(event);
|
||||
replay_mutex_lock();
|
||||
QTAILQ_REMOVE(&events_list, event, events);
|
||||
g_free(event);
|
||||
}
|
||||
@ -220,58 +214,60 @@ void replay_save_events(int checkpoint)
|
||||
static Event *replay_read_event(int checkpoint)
|
||||
{
|
||||
Event *event;
|
||||
if (read_event_kind == -1) {
|
||||
read_checkpoint = replay_get_byte();
|
||||
read_event_kind = replay_get_byte();
|
||||
read_id = -1;
|
||||
if (replay_state.read_event_kind == -1) {
|
||||
replay_state.read_event_checkpoint = replay_get_byte();
|
||||
replay_state.read_event_kind = replay_get_byte();
|
||||
replay_state.read_event_id = -1;
|
||||
replay_check_error();
|
||||
}
|
||||
|
||||
if (checkpoint != read_checkpoint) {
|
||||
if (checkpoint != replay_state.read_event_checkpoint) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Events that has not to be in the queue */
|
||||
switch (read_event_kind) {
|
||||
switch (replay_state.read_event_kind) {
|
||||
case REPLAY_ASYNC_EVENT_BH:
|
||||
if (read_id == -1) {
|
||||
read_id = replay_get_qword();
|
||||
if (replay_state.read_event_id == -1) {
|
||||
replay_state.read_event_id = replay_get_qword();
|
||||
}
|
||||
break;
|
||||
case REPLAY_ASYNC_EVENT_INPUT:
|
||||
event = g_malloc0(sizeof(Event));
|
||||
event->event_kind = read_event_kind;
|
||||
event->event_kind = replay_state.read_event_kind;
|
||||
event->opaque = replay_read_input_event();
|
||||
return event;
|
||||
case REPLAY_ASYNC_EVENT_INPUT_SYNC:
|
||||
event = g_malloc0(sizeof(Event));
|
||||
event->event_kind = read_event_kind;
|
||||
event->event_kind = replay_state.read_event_kind;
|
||||
event->opaque = 0;
|
||||
return event;
|
||||
case REPLAY_ASYNC_EVENT_CHAR_READ:
|
||||
event = g_malloc0(sizeof(Event));
|
||||
event->event_kind = read_event_kind;
|
||||
event->event_kind = replay_state.read_event_kind;
|
||||
event->opaque = replay_event_char_read_load();
|
||||
return event;
|
||||
case REPLAY_ASYNC_EVENT_BLOCK:
|
||||
if (read_id == -1) {
|
||||
read_id = replay_get_qword();
|
||||
if (replay_state.read_event_id == -1) {
|
||||
replay_state.read_event_id = replay_get_qword();
|
||||
}
|
||||
break;
|
||||
case REPLAY_ASYNC_EVENT_NET:
|
||||
event = g_malloc0(sizeof(Event));
|
||||
event->event_kind = read_event_kind;
|
||||
event->event_kind = replay_state.read_event_kind;
|
||||
event->opaque = replay_event_net_load();
|
||||
return event;
|
||||
default:
|
||||
error_report("Unknown ID %d of replay event", read_event_kind);
|
||||
error_report("Unknown ID %d of replay event",
|
||||
replay_state.read_event_kind);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(event, &events_list, events) {
|
||||
if (event->event_kind == read_event_kind
|
||||
&& (read_id == -1 || read_id == event->id)) {
|
||||
if (event->event_kind == replay_state.read_event_kind
|
||||
&& (replay_state.read_event_id == -1
|
||||
|| replay_state.read_event_id == event->id)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -290,24 +286,23 @@ static Event *replay_read_event(int checkpoint)
|
||||
/* Called with replay mutex locked */
|
||||
void replay_read_events(int checkpoint)
|
||||
{
|
||||
g_assert(replay_mutex_locked());
|
||||
while (replay_state.data_kind == EVENT_ASYNC) {
|
||||
Event *event = replay_read_event(checkpoint);
|
||||
if (!event) {
|
||||
break;
|
||||
}
|
||||
replay_mutex_unlock();
|
||||
replay_finish_event();
|
||||
replay_state.read_event_kind = -1;
|
||||
replay_run_event(event);
|
||||
replay_mutex_lock();
|
||||
|
||||
g_free(event);
|
||||
replay_finish_event();
|
||||
read_event_kind = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void replay_init_events(void)
|
||||
{
|
||||
read_event_kind = -1;
|
||||
replay_state.read_event_kind = -1;
|
||||
}
|
||||
|
||||
void replay_finish_events(void)
|
||||
|
@ -24,12 +24,23 @@
|
||||
static QemuMutex lock;
|
||||
|
||||
/* File for replay writing */
|
||||
static bool write_error;
|
||||
FILE *replay_file;
|
||||
|
||||
static void replay_write_error(void)
|
||||
{
|
||||
if (!write_error) {
|
||||
error_report("replay write error");
|
||||
write_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
void replay_put_byte(uint8_t byte)
|
||||
{
|
||||
if (replay_file) {
|
||||
putc(byte, replay_file);
|
||||
if (putc(byte, replay_file) == EOF) {
|
||||
replay_write_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +73,9 @@ void replay_put_array(const uint8_t *buf, size_t size)
|
||||
{
|
||||
if (replay_file) {
|
||||
replay_put_dword(size);
|
||||
fwrite(buf, 1, size, replay_file);
|
||||
if (fwrite(buf, 1, size, replay_file) != size) {
|
||||
replay_write_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,31 +182,46 @@ void replay_finish_event(void)
|
||||
replay_fetch_data_kind();
|
||||
}
|
||||
|
||||
static __thread bool replay_locked;
|
||||
|
||||
void replay_mutex_init(void)
|
||||
{
|
||||
qemu_mutex_init(&lock);
|
||||
/* Hold the mutex while we start-up */
|
||||
qemu_mutex_lock(&lock);
|
||||
replay_locked = true;
|
||||
}
|
||||
|
||||
void replay_mutex_destroy(void)
|
||||
bool replay_mutex_locked(void)
|
||||
{
|
||||
qemu_mutex_destroy(&lock);
|
||||
return replay_locked;
|
||||
}
|
||||
|
||||
/* Ordering constraints, replay_lock must be taken before BQL */
|
||||
void replay_mutex_lock(void)
|
||||
{
|
||||
qemu_mutex_lock(&lock);
|
||||
if (replay_mode != REPLAY_MODE_NONE) {
|
||||
g_assert(!qemu_mutex_iothread_locked());
|
||||
g_assert(!replay_mutex_locked());
|
||||
qemu_mutex_lock(&lock);
|
||||
replay_locked = true;
|
||||
}
|
||||
}
|
||||
|
||||
void replay_mutex_unlock(void)
|
||||
{
|
||||
qemu_mutex_unlock(&lock);
|
||||
if (replay_mode != REPLAY_MODE_NONE) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_locked = false;
|
||||
qemu_mutex_unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Saves cached instructions. */
|
||||
void replay_save_instructions(void)
|
||||
{
|
||||
if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
int diff = (int)(replay_get_current_step() - replay_state.current_step);
|
||||
|
||||
/* Time can only go forward */
|
||||
@ -204,6 +232,5 @@ void replay_save_instructions(void)
|
||||
replay_put_dword(diff);
|
||||
replay_state.current_step += diff;
|
||||
}
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Any changes to order/number of events will need to bump REPLAY_VERSION */
|
||||
enum ReplayEvents {
|
||||
/* for instruction event */
|
||||
EVENT_INSTRUCTION,
|
||||
@ -78,6 +78,14 @@ typedef struct ReplayState {
|
||||
This counter is global, because requests from different
|
||||
block devices should not get overlapping ids. */
|
||||
uint64_t block_request_id;
|
||||
/*! Prior value of the host clock */
|
||||
uint64_t host_clock_last;
|
||||
/*! Asynchronous event type read from the log */
|
||||
int32_t read_event_kind;
|
||||
/*! Asynchronous event id read from the log */
|
||||
uint64_t read_event_id;
|
||||
/*! Asynchronous event checkpoint id read from the log */
|
||||
int32_t read_event_checkpoint;
|
||||
} ReplayState;
|
||||
extern ReplayState replay_state;
|
||||
|
||||
@ -98,12 +106,11 @@ int64_t replay_get_qword(void);
|
||||
void replay_get_array(uint8_t *buf, size_t *size);
|
||||
void replay_get_array_alloc(uint8_t **buf, size_t *size);
|
||||
|
||||
/* Mutex functions for protecting replay log file */
|
||||
/* Mutex functions for protecting replay log file and ensuring
|
||||
* synchronisation between vCPU and main-loop threads. */
|
||||
|
||||
void replay_mutex_init(void);
|
||||
void replay_mutex_destroy(void);
|
||||
void replay_mutex_lock(void);
|
||||
void replay_mutex_unlock(void);
|
||||
bool replay_mutex_locked(void);
|
||||
|
||||
/*! Checks error status of the file. */
|
||||
void replay_check_error(void);
|
||||
|
@ -25,6 +25,7 @@ static int replay_pre_save(void *opaque)
|
||||
{
|
||||
ReplayState *state = opaque;
|
||||
state->file_offset = ftell(replay_file);
|
||||
state->host_clock_last = qemu_clock_get_last(QEMU_CLOCK_HOST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -33,6 +34,7 @@ static int replay_post_load(void *opaque, int version_id)
|
||||
{
|
||||
ReplayState *state = opaque;
|
||||
fseek(replay_file, state->file_offset, SEEK_SET);
|
||||
qemu_clock_set_last(QEMU_CLOCK_HOST, state->host_clock_last);
|
||||
/* If this was a vmstate, saved in recording mode,
|
||||
we need to initialize replay data fields. */
|
||||
replay_fetch_data_kind();
|
||||
@ -54,6 +56,10 @@ static const VMStateDescription vmstate_replay = {
|
||||
VMSTATE_UINT32(has_unread_data, ReplayState),
|
||||
VMSTATE_UINT64(file_offset, ReplayState),
|
||||
VMSTATE_UINT64(block_request_id, ReplayState),
|
||||
VMSTATE_UINT64(host_clock_last, ReplayState),
|
||||
VMSTATE_INT32(read_event_kind, ReplayState),
|
||||
VMSTATE_UINT64(read_event_id, ReplayState),
|
||||
VMSTATE_INT32(read_event_checkpoint, ReplayState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
@ -83,3 +89,9 @@ void replay_vmstate_init(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool replay_can_snapshot(void)
|
||||
{
|
||||
return replay_mode == REPLAY_MODE_NONE
|
||||
|| !replay_has_events();
|
||||
}
|
||||
|
@ -17,13 +17,13 @@
|
||||
|
||||
int64_t replay_save_clock(ReplayClockKind kind, int64_t clock)
|
||||
{
|
||||
replay_save_instructions();
|
||||
|
||||
if (replay_file) {
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
|
||||
replay_save_instructions();
|
||||
replay_put_event(EVENT_CLOCK + kind);
|
||||
replay_put_qword(clock);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
return clock;
|
||||
@ -46,16 +46,16 @@ void replay_read_next_clock(ReplayClockKind kind)
|
||||
/*! Reads next clock event from the input. */
|
||||
int64_t replay_read_clock(ReplayClockKind kind)
|
||||
{
|
||||
g_assert(replay_file && replay_mutex_locked());
|
||||
|
||||
replay_account_executed_instructions();
|
||||
|
||||
if (replay_file) {
|
||||
int64_t ret;
|
||||
replay_mutex_lock();
|
||||
if (replay_next_event_is(EVENT_CLOCK + kind)) {
|
||||
replay_read_next_clock(kind);
|
||||
}
|
||||
ret = replay_state.cached_clock[kind];
|
||||
replay_mutex_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
/* Current version of the replay mechanism.
|
||||
Increase it when file format changes. */
|
||||
#define REPLAY_VERSION 0xe02006
|
||||
#define REPLAY_VERSION 0xe02007
|
||||
/* Size of replay log header */
|
||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
||||
|
||||
@ -81,7 +81,7 @@ int replay_get_instructions(void)
|
||||
void replay_account_executed_instructions(void)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
if (replay_state.instructions_count > 0) {
|
||||
int count = (int)(replay_get_current_step()
|
||||
- replay_state.current_step);
|
||||
@ -100,24 +100,22 @@ void replay_account_executed_instructions(void)
|
||||
qemu_notify_event();
|
||||
}
|
||||
}
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool replay_exception(void)
|
||||
{
|
||||
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_save_instructions();
|
||||
replay_mutex_lock();
|
||||
replay_put_event(EVENT_EXCEPTION);
|
||||
replay_mutex_unlock();
|
||||
return true;
|
||||
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
bool res = replay_has_exception();
|
||||
if (res) {
|
||||
replay_mutex_lock();
|
||||
replay_finish_event();
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -129,10 +127,9 @@ bool replay_has_exception(void)
|
||||
{
|
||||
bool res = false;
|
||||
if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_account_executed_instructions();
|
||||
replay_mutex_lock();
|
||||
res = replay_next_event_is(EVENT_EXCEPTION);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -141,17 +138,15 @@ bool replay_has_exception(void)
|
||||
bool replay_interrupt(void)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_save_instructions();
|
||||
replay_mutex_lock();
|
||||
replay_put_event(EVENT_INTERRUPT);
|
||||
replay_mutex_unlock();
|
||||
return true;
|
||||
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
bool res = replay_has_interrupt();
|
||||
if (res) {
|
||||
replay_mutex_lock();
|
||||
replay_finish_event();
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -163,10 +158,9 @@ bool replay_has_interrupt(void)
|
||||
{
|
||||
bool res = false;
|
||||
if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_account_executed_instructions();
|
||||
replay_mutex_lock();
|
||||
res = replay_next_event_is(EVENT_INTERRUPT);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -174,25 +168,35 @@ bool replay_has_interrupt(void)
|
||||
void replay_shutdown_request(ShutdownCause cause)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
replay_mutex_lock();
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_put_event(EVENT_SHUTDOWN + cause);
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool replay_checkpoint(ReplayCheckpoint checkpoint)
|
||||
{
|
||||
bool res = false;
|
||||
static bool in_checkpoint;
|
||||
assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
|
||||
replay_save_instructions();
|
||||
|
||||
if (!replay_file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
replay_mutex_lock();
|
||||
if (in_checkpoint) {
|
||||
/* If we are already in checkpoint, then there is no need
|
||||
for additional synchronization.
|
||||
Recursion occurs when HW event modifies timers.
|
||||
Timer modification may invoke the checkpoint and
|
||||
proceed to recursion. */
|
||||
return true;
|
||||
}
|
||||
in_checkpoint = true;
|
||||
|
||||
replay_save_instructions();
|
||||
|
||||
if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
g_assert(replay_mutex_locked());
|
||||
if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
|
||||
replay_finish_event();
|
||||
} else if (replay_state.data_kind != EVENT_ASYNC) {
|
||||
@ -205,12 +209,18 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint)
|
||||
checkpoint were processed */
|
||||
res = replay_state.data_kind != EVENT_ASYNC;
|
||||
} else if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
g_assert(replay_mutex_locked());
|
||||
replay_put_event(EVENT_CHECKPOINT + checkpoint);
|
||||
replay_save_events(checkpoint);
|
||||
/* This checkpoint belongs to several threads.
|
||||
Processing events from different threads is
|
||||
non-deterministic */
|
||||
if (checkpoint != CHECKPOINT_CLOCK_WARP_START) {
|
||||
replay_save_events(checkpoint);
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
out:
|
||||
replay_mutex_unlock();
|
||||
in_checkpoint = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -233,8 +243,6 @@ static void replay_enable(const char *fname, int mode)
|
||||
|
||||
atexit(replay_finish);
|
||||
|
||||
replay_mutex_init();
|
||||
|
||||
replay_file = fopen(fname, fmode);
|
||||
if (replay_file == NULL) {
|
||||
fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
|
||||
@ -242,8 +250,9 @@ static void replay_enable(const char *fname, int mode)
|
||||
}
|
||||
|
||||
replay_filename = g_strdup(fname);
|
||||
|
||||
replay_mode = mode;
|
||||
replay_mutex_init();
|
||||
|
||||
replay_state.data_kind = -1;
|
||||
replay_state.instructions_count = 0;
|
||||
replay_state.current_step = 0;
|
||||
@ -358,7 +367,6 @@ void replay_finish(void)
|
||||
replay_snapshot = NULL;
|
||||
|
||||
replay_finish_events();
|
||||
replay_mutex_destroy();
|
||||
}
|
||||
|
||||
void replay_add_blocker(Error *reason)
|
||||
|
@ -1447,9 +1447,10 @@ sub process {
|
||||
# check we are in a valid source file if not then ignore this hunk
|
||||
next if ($realfile !~ /$SrcFile/);
|
||||
|
||||
#90 column limit
|
||||
#90 column limit; exempt URLs, if no other words on line
|
||||
if ($line =~ /^\+/ &&
|
||||
!($line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
|
||||
!($rawline =~ /^[^[:alnum:]]*https?:\S*$/) &&
|
||||
$length > 80)
|
||||
{
|
||||
if ($length > 90) {
|
||||
|
308
scripts/replay-dump.py
Executable file
308
scripts/replay-dump.py
Executable file
@ -0,0 +1,308 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Dump the contents of a recorded execution stream
|
||||
#
|
||||
# Copyright (c) 2017 Alex Bennée <alex.bennee@linaro.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import argparse
|
||||
import struct
|
||||
from collections import namedtuple
|
||||
|
||||
# This mirrors some of the global replay state which some of the
|
||||
# stream loading refers to. Some decoders may read the next event so
|
||||
# we need handle that case. Calling reuse_event will ensure the next
|
||||
# event is read from the cache rather than advancing the file.
|
||||
|
||||
class ReplayState(object):
|
||||
def __init__(self):
|
||||
self.event = -1
|
||||
self.event_count = 0
|
||||
self.already_read = False
|
||||
self.current_checkpoint = 0
|
||||
self.checkpoint = 0
|
||||
|
||||
def set_event(self, ev):
|
||||
self.event = ev
|
||||
self.event_count += 1
|
||||
|
||||
def get_event(self):
|
||||
self.already_read = False
|
||||
return self.event
|
||||
|
||||
def reuse_event(self, ev):
|
||||
self.event = ev
|
||||
self.already_read = True
|
||||
|
||||
def set_checkpoint(self):
|
||||
self.checkpoint = self.event - self.checkpoint_start
|
||||
|
||||
def get_checkpoint(self):
|
||||
return self.checkpoint
|
||||
|
||||
replay_state = ReplayState()
|
||||
|
||||
# Simple read functions that mirror replay-internal.c
|
||||
# The file-stream is big-endian and manually written out a byte at a time.
|
||||
|
||||
def read_byte(fin):
|
||||
"Read a single byte"
|
||||
return struct.unpack('>B', fin.read(1))[0]
|
||||
|
||||
def read_event(fin):
|
||||
"Read a single byte event, but save some state"
|
||||
if replay_state.already_read:
|
||||
return replay_state.get_event()
|
||||
else:
|
||||
replay_state.set_event(read_byte(fin))
|
||||
return replay_state.event
|
||||
|
||||
def read_word(fin):
|
||||
"Read a 16 bit word"
|
||||
return struct.unpack('>H', fin.read(2))[0]
|
||||
|
||||
def read_dword(fin):
|
||||
"Read a 32 bit word"
|
||||
return struct.unpack('>I', fin.read(4))[0]
|
||||
|
||||
def read_qword(fin):
|
||||
"Read a 64 bit word"
|
||||
return struct.unpack('>Q', fin.read(8))[0]
|
||||
|
||||
# Generic decoder structure
|
||||
Decoder = namedtuple("Decoder", "eid name fn")
|
||||
|
||||
def call_decode(table, index, dumpfile):
|
||||
"Search decode table for next step"
|
||||
decoder = next((d for d in table if d.eid == index), None)
|
||||
if not decoder:
|
||||
print "Could not decode index: %d" % (index)
|
||||
print "Entry is: %s" % (decoder)
|
||||
print "Decode Table is:\n%s" % (table)
|
||||
return False
|
||||
else:
|
||||
return decoder.fn(decoder.eid, decoder.name, dumpfile)
|
||||
|
||||
# Print event
|
||||
def print_event(eid, name, string=None, event_count=None):
|
||||
"Print event with count"
|
||||
if not event_count:
|
||||
event_count = replay_state.event_count
|
||||
|
||||
if string:
|
||||
print "%d:%s(%d) %s" % (event_count, name, eid, string)
|
||||
else:
|
||||
print "%d:%s(%d)" % (event_count, name, eid)
|
||||
|
||||
|
||||
# Decoders for each event type
|
||||
|
||||
def decode_unimp(eid, name, _unused_dumpfile):
|
||||
"Unimplimented decoder, will trigger exit"
|
||||
print "%s not handled - will now stop" % (name)
|
||||
return False
|
||||
|
||||
# Checkpoint decoder
|
||||
def swallow_async_qword(eid, name, dumpfile):
|
||||
"Swallow a qword of data without looking at it"
|
||||
step_id = read_qword(dumpfile)
|
||||
print " %s(%d) @ %d" % (name, eid, step_id)
|
||||
return True
|
||||
|
||||
async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
|
||||
Decoder(1, "REPLAY_ASYNC_INPUT", decode_unimp),
|
||||
Decoder(2, "REPLAY_ASYNC_INPUT_SYNC", decode_unimp),
|
||||
Decoder(3, "REPLAY_ASYNC_CHAR_READ", decode_unimp),
|
||||
Decoder(4, "REPLAY_ASYNC_EVENT_BLOCK", decode_unimp),
|
||||
Decoder(5, "REPLAY_ASYNC_EVENT_NET", decode_unimp),
|
||||
]
|
||||
# See replay_read_events/replay_read_event
|
||||
def decode_async(eid, name, dumpfile):
|
||||
"""Decode an ASYNC event"""
|
||||
|
||||
print_event(eid, name)
|
||||
|
||||
async_event_kind = read_byte(dumpfile)
|
||||
async_event_checkpoint = read_byte(dumpfile)
|
||||
|
||||
if async_event_checkpoint != replay_state.current_checkpoint:
|
||||
print " mismatch between checkpoint %d and async data %d" % (
|
||||
replay_state.current_checkpoint, async_event_checkpoint)
|
||||
return True
|
||||
|
||||
return call_decode(async_decode_table, async_event_kind, dumpfile)
|
||||
|
||||
|
||||
def decode_instruction(eid, name, dumpfile):
|
||||
ins_diff = read_dword(dumpfile)
|
||||
print_event(eid, name, "0x%x" % (ins_diff))
|
||||
return True
|
||||
|
||||
def decode_audio_out(eid, name, dumpfile):
|
||||
audio_data = read_dword(dumpfile)
|
||||
print_event(eid, name, "%d" % (audio_data))
|
||||
return True
|
||||
|
||||
def decode_checkpoint(eid, name, dumpfile):
|
||||
"""Decode a checkpoint.
|
||||
|
||||
Checkpoints contain a series of async events with their own specific data.
|
||||
"""
|
||||
replay_state.set_checkpoint()
|
||||
# save event count as we peek ahead
|
||||
event_number = replay_state.event_count
|
||||
next_event = read_event(dumpfile)
|
||||
|
||||
# if the next event is EVENT_ASYNC there are a bunch of
|
||||
# async events to read, otherwise we are done
|
||||
if next_event != 3:
|
||||
print_event(eid, name, "no additional data", event_number)
|
||||
else:
|
||||
print_event(eid, name, "more data follows", event_number)
|
||||
|
||||
replay_state.reuse_event(next_event)
|
||||
return True
|
||||
|
||||
def decode_checkpoint_init(eid, name, dumpfile):
|
||||
print_event(eid, name)
|
||||
return True
|
||||
|
||||
def decode_interrupt(eid, name, dumpfile):
|
||||
print_event(eid, name)
|
||||
return True
|
||||
|
||||
def decode_clock(eid, name, dumpfile):
|
||||
clock_data = read_qword(dumpfile)
|
||||
print_event(eid, name, "0x%x" % (clock_data))
|
||||
return True
|
||||
|
||||
|
||||
# pre-MTTCG merge
|
||||
v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||
Decoder(2, "EVENT_EXCEPTION", decode_unimp),
|
||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
||||
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
||||
Decoder(5, "EVENT_CHAR_WRITE", decode_unimp),
|
||||
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
|
||||
Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
|
||||
Decoder(8, "EVENT_CLOCK_HOST", decode_clock),
|
||||
Decoder(9, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
|
||||
Decoder(10, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
|
||||
Decoder(11, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
|
||||
Decoder(12, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
|
||||
Decoder(13, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
|
||||
Decoder(14, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
|
||||
Decoder(15, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
|
||||
Decoder(16, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
|
||||
Decoder(17, "EVENT_CP_INIT", decode_checkpoint_init),
|
||||
Decoder(18, "EVENT_CP_RESET", decode_checkpoint),
|
||||
]
|
||||
|
||||
# post-MTTCG merge, AUDIO support added
|
||||
v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||
Decoder(2, "EVENT_EXCEPTION", decode_unimp),
|
||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
||||
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
||||
Decoder(5, "EVENT_CHAR_WRITE", decode_unimp),
|
||||
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
|
||||
Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
|
||||
Decoder(8, "EVENT_AUDIO_OUT", decode_audio_out),
|
||||
Decoder(9, "EVENT_AUDIO_IN", decode_unimp),
|
||||
Decoder(10, "EVENT_CLOCK_HOST", decode_clock),
|
||||
Decoder(11, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
|
||||
Decoder(12, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
|
||||
Decoder(13, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
|
||||
Decoder(14, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
|
||||
Decoder(15, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
|
||||
Decoder(16, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
|
||||
Decoder(17, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
|
||||
Decoder(18, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
|
||||
Decoder(19, "EVENT_CP_INIT", decode_checkpoint_init),
|
||||
Decoder(20, "EVENT_CP_RESET", decode_checkpoint),
|
||||
]
|
||||
|
||||
# Shutdown cause added
|
||||
v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||
Decoder(2, "EVENT_EXCEPTION", decode_unimp),
|
||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
||||
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
||||
Decoder(5, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
|
||||
Decoder(6, "EVENT_SHUTDOWN_HOST_QMP", decode_unimp),
|
||||
Decoder(7, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_unimp),
|
||||
Decoder(8, "EVENT_SHUTDOWN_HOST_UI", decode_unimp),
|
||||
Decoder(9, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_unimp),
|
||||
Decoder(10, "EVENT_SHUTDOWN_GUEST_RESET", decode_unimp),
|
||||
Decoder(11, "EVENT_SHUTDOWN_GUEST_PANIC", decode_unimp),
|
||||
Decoder(12, "EVENT_SHUTDOWN___MAX", decode_unimp),
|
||||
Decoder(13, "EVENT_CHAR_WRITE", decode_unimp),
|
||||
Decoder(14, "EVENT_CHAR_READ_ALL", decode_unimp),
|
||||
Decoder(15, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
|
||||
Decoder(16, "EVENT_AUDIO_OUT", decode_audio_out),
|
||||
Decoder(17, "EVENT_AUDIO_IN", decode_unimp),
|
||||
Decoder(18, "EVENT_CLOCK_HOST", decode_clock),
|
||||
Decoder(19, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
|
||||
Decoder(20, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
|
||||
Decoder(21, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
|
||||
Decoder(22, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
|
||||
Decoder(23, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
|
||||
Decoder(24, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
|
||||
Decoder(25, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
|
||||
Decoder(26, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
|
||||
Decoder(27, "EVENT_CP_INIT", decode_checkpoint_init),
|
||||
Decoder(28, "EVENT_CP_RESET", decode_checkpoint),
|
||||
]
|
||||
|
||||
def parse_arguments():
|
||||
"Grab arguments for script"
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-f", "--file", help='record/replay dump to read from',
|
||||
required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
def decode_file(filename):
|
||||
"Decode a record/replay dump"
|
||||
dumpfile = open(filename, "rb")
|
||||
|
||||
# read and throwaway the header
|
||||
version = read_dword(dumpfile)
|
||||
junk = read_qword(dumpfile)
|
||||
|
||||
print "HEADER: version 0x%x" % (version)
|
||||
|
||||
if version == 0xe02007:
|
||||
event_decode_table = v7_event_table
|
||||
replay_state.checkpoint_start = 12
|
||||
elif version == 0xe02006:
|
||||
event_decode_table = v6_event_table
|
||||
replay_state.checkpoint_start = 12
|
||||
else:
|
||||
event_decode_table = v5_event_table
|
||||
replay_state.checkpoint_start = 10
|
||||
|
||||
try:
|
||||
decode_ok = True
|
||||
while decode_ok:
|
||||
event = read_event(dumpfile)
|
||||
decode_ok = call_decode(event_decode_table, event, dumpfile)
|
||||
finally:
|
||||
dumpfile.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_arguments()
|
||||
decode_file(args.file)
|
@ -102,7 +102,7 @@ QEMU_HELP_BOTTOM "\n"
|
||||
static void version(const char *name)
|
||||
{
|
||||
printf(
|
||||
"%s " QEMU_VERSION QEMU_PKGVERSION "\n"
|
||||
"%s " QEMU_FULL_VERSION "\n"
|
||||
"Written by Paolo Bonzini.\n"
|
||||
"\n"
|
||||
QEMU_COPYRIGHT "\n"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user