diff options
129 files changed, 2869 insertions, 1413 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index a1d2b3a..f2c17be 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12,6 +12,8 @@ consult qemu-devel and not any specific individual privately. Descriptions of section entries: M: Mail patches to: FullName <address@domain> + R: Designated reviewer: FullName <address@domain> + These reviewers should be CCed on patches. L: Mailing list that is relevant to this area W: Web-page with status/info Q: Patchwork web based patch tracking system site @@ -196,8 +198,8 @@ F: hw/nios2/ F: disas/nios2.c OpenRISC -M: Jia Liu <proljc@gmail.com> -S: Maintained +M: Stafford Horne <shorne@gmail.com> +S: Odd Fixes F: target/openrisc/ F: hw/openrisc/ F: tests/tcg/openrisc/ @@ -1546,6 +1548,18 @@ F: net/colo* F: net/filter-rewriter.c F: net/filter-mirror.c +Record/replay +M: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> +R: Paolo Bonzini <pbonzini@redhat.com> +W: http://wiki.qemu.org/Features/record-replay +S: Supported +F: replay/* +F: block/blkreplay.c +F: net/filter-replay.c +F: include/sysemu/replay.h +F: docs/replay.txt +F: stubs/replay.c + Usermode Emulation ------------------ Overall diff --git a/audio/audio.c b/audio/audio.c index c8898d8..beafed2 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2028,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) sw = sw1; } QLIST_REMOVE (cap, entries); + g_free (cap->hw.mix_buf); + g_free (cap->buf); g_free (cap); } return; diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 8bfb9e7..5863803 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -88,6 +88,7 @@ static void wav_capture_destroy (void *opaque) WAVState *wav = opaque; AUD_del_capture (wav->cap, wav); + g_free (wav); } static void wav_capture_info (void *opaque) diff --git a/chardev/char-fd.c b/chardev/char-fd.c index 548dd4c..0b182c5 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -58,7 +58,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) ret = qio_channel_read( chan, (gchar *)buf, len, NULL); if (ret == 0) { - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); return FALSE; } @@ -89,9 +89,9 @@ static void fd_chr_update_read_handler(Chardev *chr, { FDChardev *s = FD_CHARDEV(chr); - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); if (s->ioc_in) { - chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in, + chr->gsource = io_add_watch_poll(chr, s->ioc_in, fd_chr_read_poll, fd_chr_read, chr, context); @@ -103,7 +103,7 @@ static void char_fd_finalize(Object *obj) Chardev *chr = CHARDEV(obj); FDChardev *s = FD_CHARDEV(obj); - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); if (s->ioc_in) { object_unref(OBJECT(s->ioc_in)); } diff --git a/chardev/char-io.c b/chardev/char-io.c index b4bb094..b5708ee 100644 --- a/chardev/char-io.c +++ b/chardev/char-io.c @@ -98,7 +98,7 @@ static GSourceFuncs io_watch_poll_funcs = { .finalize = io_watch_poll_finalize, }; -guint io_add_watch_poll(Chardev *chr, +GSource *io_add_watch_poll(Chardev *chr, QIOChannel *ioc, IOCanReadHandler *fd_can_read, QIOChannelFunc fd_read, @@ -106,7 +106,6 @@ guint io_add_watch_poll(Chardev *chr, GMainContext *context) { IOWatchPoll *iwp; - int tag; char *name; iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, @@ -122,21 +121,15 @@ guint io_add_watch_poll(Chardev *chr, g_source_set_name((GSource *)iwp, name); g_free(name); - tag = g_source_attach(&iwp->parent, context); + g_source_attach(&iwp->parent, context); g_source_unref(&iwp->parent); - return tag; + return (GSource *)iwp; } -static void io_remove_watch_poll(guint tag, GMainContext *context) +static void io_remove_watch_poll(GSource *source) { - GSource *source; IOWatchPoll *iwp; - g_return_if_fail(tag > 0); - - source = g_main_context_find_source_by_id(context, tag); - g_return_if_fail(source != NULL); - iwp = io_watch_poll_from_source(source); if (iwp->src) { g_source_destroy(iwp->src); @@ -146,11 +139,11 @@ static void io_remove_watch_poll(guint tag, GMainContext *context) g_source_destroy(&iwp->parent); } -void remove_fd_in_watch(Chardev *chr, GMainContext *context) +void remove_fd_in_watch(Chardev *chr) { - if (chr->fd_in_tag) { - io_remove_watch_poll(chr->fd_in_tag, context); - chr->fd_in_tag = 0; + if (chr->gsource) { + io_remove_watch_poll(chr->gsource); + chr->gsource = NULL; } } diff --git a/chardev/char-io.h b/chardev/char-io.h index 842be56..55973a7 100644 --- a/chardev/char-io.h +++ b/chardev/char-io.h @@ -29,14 +29,14 @@ #include "sysemu/char.h" /* Can only be used for read */ -guint io_add_watch_poll(Chardev *chr, +GSource *io_add_watch_poll(Chardev *chr, QIOChannel *ioc, IOCanReadHandler *fd_can_read, QIOChannelFunc fd_read, gpointer user_data, GMainContext *context); -void remove_fd_in_watch(Chardev *chr, GMainContext *context); +void remove_fd_in_watch(Chardev *chr); int io_channel_send(QIOChannel *ioc, const void *buf, size_t len); diff --git a/chardev/char-mux.c b/chardev/char-mux.c index 5547a36..37d42c6 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -114,7 +114,7 @@ static void mux_print_help(Chardev *chr) } } -void mux_chr_send_event(MuxChardev *d, int mux_nr, int event) +static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event) { CharBackend *be = d->backends[mux_nr]; @@ -222,9 +222,9 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size) bool muxes_realized; -static void mux_chr_event(void *opaque, int event) +void mux_chr_send_all_event(Chardev *chr, int event) { - MuxChardev *d = MUX_CHARDEV(opaque); + MuxChardev *d = MUX_CHARDEV(chr); int i; if (!muxes_realized) { @@ -237,6 +237,11 @@ static void mux_chr_event(void *opaque, int event) } } +static void mux_chr_event(void *opaque, int event) +{ + mux_chr_send_all_event(CHARDEV(opaque), event); +} + static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond) { MuxChardev *d = MUX_CHARDEV(s); diff --git a/chardev/char-mux.h b/chardev/char-mux.h index 9a2fffc..3f41dfc 100644 --- a/chardev/char-mux.h +++ b/chardev/char-mux.h @@ -58,6 +58,6 @@ typedef struct MuxChardev { void mux_chr_set_handlers(Chardev *chr, GMainContext *context); void mux_set_focus(Chardev *chr, int focus); -void mux_chr_send_event(MuxChardev *d, int mux_nr, int event); +void mux_chr_send_all_event(Chardev *chr, int event); #endif /* CHAR_MUX_H */ diff --git a/chardev/char-pty.c b/chardev/char-pty.c index a6337be..35a175d 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -185,7 +185,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque) PtyChardev *s = PTY_CHARDEV(opaque); s->open_tag = 0; - qemu_chr_be_generic_open(chr); + qemu_chr_be_event(chr, CHR_EVENT_OPENED); return FALSE; } @@ -199,7 +199,7 @@ static void pty_chr_state(Chardev *chr, int connected) g_source_remove(s->open_tag); s->open_tag = 0; } - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); s->connected = 0; /* (re-)connect poll interval for idle guests: once per second. * We check more frequently in case the guests sends data to @@ -215,8 +215,8 @@ static void pty_chr_state(Chardev *chr, int connected) s->connected = 1; s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr); } - if (!chr->fd_in_tag) { - chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, + if (!chr->gsource) { + chr->gsource = io_add_watch_poll(chr, s->ioc, pty_chr_read_poll, pty_chr_read, chr, NULL); diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 36ab0d6..3bda89a 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -55,6 +55,7 @@ typedef struct { SocketAddress *addr; bool is_listen; bool is_telnet; + bool is_tn3270; guint reconnect_timer; int64_t reconnect_time; @@ -141,19 +142,25 @@ static int tcp_chr_read_poll(void *opaque) return s->max_size; } -#define IAC 255 -#define IAC_BREAK 243 static void tcp_chr_process_IAC_bytes(Chardev *chr, SocketChardev *s, uint8_t *buf, int *size) { - /* Handle any telnet client's basic IAC options to satisfy char by - * char mode with no echo. All IAC options will be removed from - * the buf and the do_telnetopt variable will be used to track the - * state of the width of the IAC information. + /* Handle any telnet or tn3270 client's basic IAC options. + * For telnet options, it satisfies char by char mode with no echo. + * For tn3270 options, it satisfies binary mode with EOR. + * All IAC options will be removed from the buf and the do_opt + * pointer will be used to track the state of the width of the + * IAC information. * - * IAC commands come in sets of 3 bytes with the exception of the - * "IAC BREAK" command and the double IAC. + * RFC854: "All TELNET commands consist of at least a two byte sequence. + * The commands dealing with option negotiation are three byte sequences, + * the third byte being the code for the option referenced." + * "IAC BREAK", "IAC IP", "IAC NOP" and the double IAC are two bytes. + * "IAC SB", "IAC SE" and "IAC EOR" are saved to split up data boundary + * for tn3270. + * NOP, Break and Interrupt Process(IP) might be encountered during a TN3270 + * session, and NOP and IP need to be done later. */ int i; @@ -174,6 +181,18 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr, /* Handle IAC break commands by sending a serial break */ qemu_chr_be_event(chr, CHR_EVENT_BREAK); s->do_telnetopt++; + } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_EOR + || (unsigned char)buf[i] == IAC_SB + || (unsigned char)buf[i] == IAC_SE) + && s->do_telnetopt == 2) { + buf[j++] = IAC; + buf[j++] = buf[i]; + s->do_telnetopt++; + } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_IP + || (unsigned char)buf[i] == IAC_NOP) + && s->do_telnetopt == 2) { + /* TODO: IP and NOP need to be implemented later. */ + s->do_telnetopt++; } s->do_telnetopt++; } @@ -327,7 +346,7 @@ static void tcp_chr_free_connection(Chardev *chr) } tcp_set_msgfds(chr, NULL, 0); - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); object_unref(OBJECT(s->sioc)); s->sioc = NULL; object_unref(OBJECT(s->ioc)); @@ -366,6 +385,15 @@ static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr, } } +static void update_disconnected_filename(SocketChardev *s) +{ + Chardev *chr = CHARDEV(s); + + g_free(chr->filename); + chr->filename = SocketAddress_to_str("disconnected:", s->addr, + s->is_listen, s->is_telnet); +} + static void tcp_chr_disconnect(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); @@ -380,8 +408,7 @@ static void tcp_chr_disconnect(Chardev *chr) s->listen_tag = qio_channel_add_watch( QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); } - chr->filename = SocketAddress_to_str("disconnected:", s->addr, - s->is_listen, s->is_telnet); + update_disconnected_filename(s); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); if (s->reconnect_time) { qemu_chr_socket_restart_timer(chr); @@ -484,12 +511,12 @@ static void tcp_chr_connect(void *opaque) s->connected = 1; if (s->ioc) { - chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, + chr->gsource = io_add_watch_poll(chr, s->ioc, tcp_chr_read_poll, tcp_chr_read, chr, NULL); } - qemu_chr_be_generic_open(chr); + qemu_chr_be_event(chr, CHR_EVENT_OPENED); } static void tcp_chr_update_read_handler(Chardev *chr, @@ -501,9 +528,9 @@ static void tcp_chr_update_read_handler(Chardev *chr, return; } - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); if (s->ioc) { - chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, + chr->gsource = io_add_watch_poll(chr, s->ioc, tcp_chr_read_poll, tcp_chr_read, chr, context); @@ -512,7 +539,7 @@ static void tcp_chr_update_read_handler(Chardev *chr, typedef struct { Chardev *chr; - char buf[12]; + char buf[21]; size_t buflen; } TCPChardevTelnetInit; @@ -550,9 +577,6 @@ static void tcp_chr_telnet_init(Chardev *chr) TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1); size_t n = 0; - init->chr = chr; - init->buflen = 12; - #define IACSET(x, a, b, c) \ do { \ x[n++] = a; \ @@ -560,12 +584,26 @@ static void tcp_chr_telnet_init(Chardev *chr) x[n++] = c; \ } while (0) - /* Prep the telnet negotion to put telnet in binary, - * no echo, single char mode */ - IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */ - IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */ - IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */ - IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */ + init->chr = chr; + if (!s->is_tn3270) { + init->buflen = 12; + /* Prep the telnet negotion to put telnet in binary, + * no echo, single char mode */ + IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */ + IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */ + IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */ + IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */ + } else { + init->buflen = 21; + /* Prep the TN3270 negotion based on RFC1576 */ + IACSET(init->buf, 0xff, 0xfd, 0x19); /* IAC DO EOR */ + IACSET(init->buf, 0xff, 0xfb, 0x19); /* IAC WILL EOR */ + IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO BINARY */ + IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL BINARY */ + IACSET(init->buf, 0xff, 0xfd, 0x18); /* IAC DO TERMINAL TYPE */ + IACSET(init->buf, 0xff, 0xfa, 0x18); /* IAC SB TERMINAL TYPE */ + IACSET(init->buf, 0x01, 0xff, 0xf0); /* SEND IAC SE */ + } #undef IACSET @@ -585,7 +623,8 @@ static void tcp_chr_tls_handshake(QIOTask *task, if (qio_task_propagate_error(task, NULL)) { tcp_chr_disconnect(chr); } else { - if (s->do_telnetopt) { + /* tn3270 does not support TLS yet */ + if (s->do_telnetopt && !s->is_tn3270) { tcp_chr_telnet_init(chr); } else { tcp_chr_connect(chr); @@ -824,12 +863,14 @@ static void qmp_chardev_open_socket(Chardev *chr, bool do_nodelay = sock->has_nodelay ? sock->nodelay : false; bool is_listen = sock->has_server ? sock->server : true; bool is_telnet = sock->has_telnet ? sock->telnet : false; + bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false; bool is_waitconnect = sock->has_wait ? sock->wait : false; int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0; QIOChannelSocket *sioc = NULL; s->is_listen = is_listen; s->is_telnet = is_telnet; + s->is_tn3270 = is_tn3270; s->do_nodelay = do_nodelay; if (sock->tls_creds) { Object *creds; @@ -875,11 +916,10 @@ static void qmp_chardev_open_socket(Chardev *chr, /* be isn't opened until we get a connection */ *be_opened = false; - chr->filename = SocketAddress_to_str("disconnected:", - addr, is_listen, is_telnet); + update_disconnected_filename(s); if (is_listen) { - if (is_telnet) { + if (is_telnet || is_tn3270) { s->do_telnetopt = 1; } } else if (reconnect > 0) { @@ -904,6 +944,11 @@ static void qmp_chardev_open_socket(Chardev *chr, if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) { goto error; } + + qapi_free_SocketAddress(s->addr); + s->addr = socket_local_address(sioc->fd, errp); + update_disconnected_filename(s); + s->listen_ioc = sioc; if (is_waitconnect && qemu_chr_wait_connected(chr, errp) < 0) { @@ -933,6 +978,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, bool is_listen = qemu_opt_get_bool(opts, "server", false); bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true); bool is_telnet = qemu_opt_get_bool(opts, "telnet", false); + bool is_tn3270 = qemu_opt_get_bool(opts, "tn3270", false); bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true); int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0); const char *path = qemu_opt_get(opts, "path"); @@ -968,6 +1014,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, sock->server = is_listen; sock->has_telnet = true; sock->telnet = is_telnet; + sock->has_tn3270 = true; + sock->tn3270 = is_tn3270; sock->has_wait = true; sock->wait = is_waitconnect; sock->has_reconnect = true; @@ -997,6 +1045,23 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, sock->addr = addr; } +static void +char_socket_get_addr(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + SocketChardev *s = SOCKET_CHARDEV(obj); + + visit_type_SocketAddress(v, name, &s->addr, errp); +} + +static bool +char_socket_get_connected(Object *obj, Error **errp) +{ + SocketChardev *s = SOCKET_CHARDEV(obj); + + return s->connected; +} + static void char_socket_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -1012,6 +1077,13 @@ 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; + + object_class_property_add(oc, "addr", "SocketAddress", + char_socket_get_addr, NULL, + NULL, NULL, &error_abort); + + object_class_property_add_bool(oc, "connected", char_socket_get_connected, + NULL, &error_abort); } static const TypeInfo char_socket_type_info = { diff --git a/chardev/char-udp.c b/chardev/char-udp.c index 804bd22..76ef83f 100644 --- a/chardev/char-udp.c +++ b/chardev/char-udp.c @@ -51,6 +51,18 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) s->ioc, (const char *)buf, len, NULL); } +static void udp_chr_flush_buffer(UdpChardev *s) +{ + Chardev *chr = CHARDEV(s); + + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + int n = MIN(s->max_size, s->bufcnt - s->bufptr); + qemu_chr_be_write(chr, &s->buf[s->bufptr], n); + s->bufptr += n; + s->max_size = qemu_chr_be_can_write(chr); + } +} + static int udp_chr_read_poll(void *opaque) { Chardev *chr = CHARDEV(opaque); @@ -61,11 +73,8 @@ static int udp_chr_read_poll(void *opaque) /* If there were any stray characters in the queue process them * first */ - while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); - s->bufptr++; - s->max_size = qemu_chr_be_can_write(chr); - } + udp_chr_flush_buffer(s); + return s->max_size; } @@ -81,17 +90,12 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) ret = qio_channel_read( s->ioc, (char *)s->buf, sizeof(s->buf), NULL); if (ret <= 0) { - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); return FALSE; } s->bufcnt = ret; - s->bufptr = 0; - while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); - s->bufptr++; - s->max_size = qemu_chr_be_can_write(chr); - } + udp_chr_flush_buffer(s); return TRUE; } @@ -101,9 +105,9 @@ static void udp_chr_update_read_handler(Chardev *chr, { UdpChardev *s = UDP_CHARDEV(chr); - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); if (s->ioc) { - chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, + chr->gsource = io_add_watch_poll(chr, s->ioc, udp_chr_read_poll, udp_chr_read, chr, context); @@ -115,7 +119,7 @@ static void char_udp_finalize(Object *obj) Chardev *chr = CHARDEV(obj); UdpChardev *s = UDP_CHARDEV(obj); - remove_fd_in_watch(chr, NULL); + remove_fd_in_watch(chr); if (s->ioc) { object_unref(OBJECT(s->ioc)); } diff --git a/chardev/char.c b/chardev/char.c index 3df1163..4e24dc3 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -42,8 +42,10 @@ /***********************************************************/ /* character device */ -static QTAILQ_HEAD(ChardevHead, Chardev) chardevs = - QTAILQ_HEAD_INITIALIZER(chardevs); +static Object *get_chardevs_root(void) +{ + return container_get(object_get_root(), "/chardevs"); +} void qemu_chr_be_event(Chardev *s, int event) { @@ -66,12 +68,6 @@ void qemu_chr_be_event(Chardev *s, int event) be->chr_event(be->opaque, event); } -void qemu_chr_be_generic_open(Chardev *s) -{ - qemu_chr_be_event(s, CHR_EVENT_OPENED); -} - - /* Not reporting errors from writing to logfile, as logs are * defined to be "best effort" only */ static void qemu_chr_fe_write_log(Chardev *s, @@ -453,26 +449,24 @@ static const TypeInfo char_type_info = { * mux will receive CHR_EVENT_OPENED notifications for the BE * immediately. */ -static void muxes_realize_done(Notifier *notifier, void *unused) +static int open_muxes(Object *child, void *opaque) { - Chardev *chr; + 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); + } - QTAILQ_FOREACH(chr, &chardevs, next) { - if (CHARDEV_IS_MUX(chr)) { - MuxChardev *d = MUX_CHARDEV(chr); - int i; + return 0; +} - /* send OPENED to all already-attached FEs */ - for (i = 0; i < d->mux_cnt; i++) { - mux_chr_send_event(d, i, CHR_EVENT_OPENED); - } - /* mark mux as OPENED so any new FEs will immediately receive - * OPENED event - */ - qemu_chr_be_generic_open(chr); - } - } +static void muxes_realize_done(Notifier *notifier, void *unused) +{ muxes_realized = true; + object_child_foreach(get_chardevs_root(), open_muxes, NULL); } static Notifier muxes_realize_notify = { @@ -560,7 +554,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b, cc = CHARDEV_GET_CLASS(s); if (!opaque && !fd_can_read && !fd_read && !fd_event) { fe_open = 0; - remove_fd_in_watch(s, context); + remove_fd_in_watch(s); } else { fe_open = 1; } @@ -581,7 +575,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b, /* We're connecting to an already opened device, so let's make sure we also get the open event */ if (s->be_open) { - qemu_chr_be_generic_open(s); + qemu_chr_be_event(s, CHR_EVENT_OPENED); } } @@ -696,7 +690,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) return opts; } if (strstart(filename, "tcp:", &p) || - strstart(filename, "telnet:", &p)) { + strstart(filename, "telnet:", &p) || + strstart(filename, "tn3270:", &p)) { if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) @@ -712,8 +707,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) goto fail; } } - if (strstart(filename, "telnet:", &p)) + if (strstart(filename, "telnet:", &p)) { qemu_opt_set(opts, "telnet", "on", &error_abort); + } else if (strstart(filename, "tn3270:", &p)) { + qemu_opt_set(opts, "tn3270", "on", &error_abort); + } return opts; } if (strstart(filename, "udp:", &p)) { @@ -770,7 +768,7 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend) const char *logfile = qemu_opt_get(opts, "logfile"); backend->has_logfile = logfile != NULL; - backend->logfile = logfile ? g_strdup(logfile) : NULL; + backend->logfile = g_strdup(logfile); backend->has_logappend = true; backend->logappend = qemu_opt_get_bool(opts, "logappend", false); @@ -805,26 +803,6 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp) return cc; } -static Chardev *qemu_chardev_add(const char *id, const char *typename, - ChardevBackend *backend, Error **errp) -{ - Chardev *chr; - - chr = qemu_chr_find(id); - if (chr) { - error_setg(errp, "Chardev '%s' already exists", id); - return NULL; - } - - chr = qemu_chardev_new(id, typename, backend, errp); - if (!chr) { - return NULL; - } - - QTAILQ_INSERT_TAIL(&chardevs, chr, next); - return chr; -} - static const struct ChardevAlias { const char *typename; const char *alias; @@ -941,9 +919,10 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, backend->u.null.data = ccom; /* Any ChardevCommon member would work */ } - chr = qemu_chardev_add(bid ? bid : id, + chr = qemu_chardev_new(bid ? bid : id, object_class_get_name(OBJECT_CLASS(cc)), backend, errp); + if (chr == NULL) { goto out; } @@ -955,9 +934,9 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, backend->type = CHARDEV_BACKEND_KIND_MUX; backend->u.mux.data = g_new0(ChardevMux, 1); backend->u.mux.data->chardev = g_strdup(bid); - mux = qemu_chardev_add(id, TYPE_CHARDEV_MUX, backend, errp); + mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, errp); if (mux == NULL) { - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); chr = NULL; goto out; } @@ -1071,27 +1050,29 @@ void qemu_chr_fe_disconnect(CharBackend *be) } } -void qemu_chr_delete(Chardev *chr) +static int qmp_query_chardev_foreach(Object *obj, void *data) { - QTAILQ_REMOVE(&chardevs, chr, next); - object_unref(OBJECT(chr)); + Chardev *chr = CHARDEV(obj); + ChardevInfoList **list = data; + ChardevInfoList *info = g_malloc0(sizeof(*info)); + + info->value = g_malloc0(sizeof(*info->value)); + info->value->label = g_strdup(chr->label); + info->value->filename = g_strdup(chr->filename); + info->value->frontend_open = chr->be && chr->be->fe_open; + + info->next = *list; + *list = info; + + return 0; } ChardevInfoList *qmp_query_chardev(Error **errp) { ChardevInfoList *chr_list = NULL; - Chardev *chr; - - QTAILQ_FOREACH(chr, &chardevs, next) { - ChardevInfoList *info = g_malloc0(sizeof(*info)); - info->value = g_malloc0(sizeof(*info->value)); - info->value->label = g_strdup(chr->label); - info->value->filename = g_strdup(chr->filename); - info->value->frontend_open = chr->be && chr->be->fe_open; - info->next = chr_list; - chr_list = info; - } + object_child_foreach(get_chardevs_root(), + qmp_query_chardev_foreach, &chr_list); return chr_list; } @@ -1119,14 +1100,9 @@ ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp) Chardev *qemu_chr_find(const char *name) { - Chardev *chr; + Object *obj = object_resolve_path_component(get_chardevs_root(), name); - QTAILQ_FOREACH(chr, &chardevs, next) { - if (strcmp(chr->label, name) != 0) - continue; - return chr; - } - return NULL; + return obj ? CHARDEV(obj) : NULL; } QemuOptsList qemu_chardev_opts = { @@ -1177,6 +1153,9 @@ QemuOptsList qemu_chardev_opts = { .name = "telnet", .type = QEMU_OPT_BOOL, },{ + .name = "tn3270", + .type = QEMU_OPT_BOOL, + },{ .name = "tls-creds", .type = QEMU_OPT_STRING, },{ @@ -1236,22 +1215,23 @@ void qemu_chr_set_feature(Chardev *chr, } Chardev *qemu_chardev_new(const char *id, const char *typename, - ChardevBackend *backend, Error **errp) + ChardevBackend *backend, + Error **errp) { + Object *obj; Chardev *chr = NULL; Error *local_err = NULL; bool be_opened = true; assert(g_str_has_prefix(typename, "chardev-")); - chr = CHARDEV(object_new(typename)); + obj = object_new(typename); + chr = CHARDEV(obj); chr->label = g_strdup(id); qemu_char_open(chr, backend, &be_opened, &local_err); if (local_err) { - error_propagate(errp, local_err); - object_unref(OBJECT(chr)); - return NULL; + goto end; } if (!chr->filename) { @@ -1261,6 +1241,21 @@ Chardev *qemu_chardev_new(const char *id, const char *typename, qemu_chr_be_event(chr, CHR_EVENT_OPENED); } + if (id) { + object_property_add_child(get_chardevs_root(), id, obj, &local_err); + if (local_err) { + goto end; + } + object_unref(obj); + } + +end: + if (local_err) { + error_propagate(errp, local_err); + object_unref(obj); + return NULL; + } + return chr; } @@ -1276,7 +1271,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, return NULL; } - chr = qemu_chardev_add(id, object_class_get_name(OBJECT_CLASS(cc)), + chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)), backend, errp); if (!chr) { return NULL; @@ -1309,16 +1304,12 @@ void qmp_chardev_remove(const char *id, Error **errp) "Chardev '%s' cannot be unplugged in record/replay mode", id); return; } - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); } void qemu_chr_cleanup(void) { - Chardev *chr, *tmp; - - QTAILQ_FOREACH_SAFE(chr, &chardevs, next, tmp) { - qemu_chr_delete(chr); - } + object_unparent(get_chardevs_root()); } static void register_types(void) @@ -4853,6 +4853,20 @@ EOF fi ########################################## +# check for _Static_assert() + +have_static_assert=no +cat > $TMPC << EOF +_Static_assert(1, "success"); +int main(void) { + return 0; +} +EOF +if compile_prog "" "" ; then + have_static_assert=yes +fi + +########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -5848,6 +5862,10 @@ if test "$have_sysmacros" = "yes" ; then echo "CONFIG_SYSMACROS=y" >> $config_host_mak fi +if test "$have_static_assert" = "yes" ; then + echo "CONFIG_STATIC_ASSERT=y" >> $config_host_mak +fi + # Hold two types of flag: # CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on # a thread we have a handle to @@ -6023,9 +6041,11 @@ TARGET_ABI_DIR="" case "$target_name" in i386) + gdb_xml_files="i386-32bit-core.xml" ;; x86_64) TARGET_BASE_ARCH=i386 + gdb_xml_files="i386-64bit-core.xml" ;; alpha) mttcg="yes" diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index af4faad..61e1657 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -81,7 +81,7 @@ vu_panic(VuDev *dev, const char *msg, ...) va_list ap; va_start(ap, msg); - (void)vasprintf(&buf, msg, ap); + buf = g_strdup_vprintf(msg, ap); va_end(ap); dev->broken = true; diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index 36e15de..9615a48 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -2,6 +2,7 @@ CONFIG_PCI=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO=y CONFIG_SCLPCONSOLE=y +CONFIG_TERMINAL3270=y CONFIG_S390_FLIC=y CONFIG_S390_FLIC_KVM=$(CONFIG_KVM) CONFIG_WDT_DIAG288=y @@ -77,7 +77,13 @@ static int dump_cleanup(DumpState *s) memory_mapping_list_free(&s->list); close(s->fd); if (s->resume) { + if (s->detached) { + qemu_mutex_lock_iothread(); + } vm_start(); + if (s->detached) { + qemu_mutex_unlock_iothread(); + } } return 0; @@ -1804,6 +1810,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, if (detach_p) { /* detached dump */ + s->detached = true; qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread, s, QEMU_THREAD_DETACHED); } else { diff --git a/gdb-xml/i386-32bit-core.xml b/gdb-xml/i386-32bit-core.xml new file mode 100644 index 0000000..7aeeeca --- /dev/null +++ b/gdb-xml/i386-32bit-core.xml @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.i386.core"> + <flags id="i386_eflags" size="4"> + <field name="CF" start="0" end="0"/> + <field name="" start="1" end="1"/> + <field name="PF" start="2" end="2"/> + <field name="AF" start="4" end="4"/> + <field name="ZF" start="6" end="6"/> + <field name="SF" start="7" end="7"/> + <field name="TF" start="8" end="8"/> + <field name="IF" start="9" end="9"/> + <field name="DF" start="10" end="10"/> + <field name="OF" start="11" end="11"/> + <field name="NT" start="14" end="14"/> + <field name="RF" start="16" end="16"/> + <field name="VM" start="17" end="17"/> + <field name="AC" start="18" end="18"/> + <field name="VIF" start="19" end="19"/> + <field name="VIP" start="20" end="20"/> + <field name="ID" start="21" end="21"/> + </flags> + + <reg name="eax" bitsize="32" type="int32"/> + <reg name="ecx" bitsize="32" type="int32"/> + <reg name="edx" bitsize="32" type="int32"/> + <reg name="ebx" bitsize="32" type="int32"/> + <reg name="esp" bitsize="32" type="data_ptr"/> + <reg name="ebp" bitsize="32" type="data_ptr"/> + <reg name="esi" bitsize="32" type="int32"/> + <reg name="edi" bitsize="32" type="int32"/> + + <reg name="eip" bitsize="32" type="code_ptr"/> + <reg name="eflags" bitsize="32" type="i386_eflags"/> + <reg name="cs" bitsize="32" type="int32"/> + <reg name="ss" bitsize="32" type="int32"/> + <reg name="ds" bitsize="32" type="int32"/> + <reg name="es" bitsize="32" type="int32"/> + <reg name="fs" bitsize="32" type="int32"/> + <reg name="gs" bitsize="32" type="int32"/> + + <reg name="st0" bitsize="80" type="i387_ext"/> + <reg name="st1" bitsize="80" type="i387_ext"/> + <reg name="st2" bitsize="80" type="i387_ext"/> + <reg name="st3" bitsize="80" type="i387_ext"/> + <reg name="st4" bitsize="80" type="i387_ext"/> + <reg name="st5" bitsize="80" type="i387_ext"/> + <reg name="st6" bitsize="80" type="i387_ext"/> + <reg name="st7" bitsize="80" type="i387_ext"/> + + <reg name="fctrl" bitsize="32" type="int" group="float"/> + <reg name="fstat" bitsize="32" type="int" group="float"/> + <reg name="ftag" bitsize="32" type="int" group="float"/> + <reg name="fiseg" bitsize="32" type="int" group="float"/> + <reg name="fioff" bitsize="32" type="int" group="float"/> + <reg name="foseg" bitsize="32" type="int" group="float"/> + <reg name="fooff" bitsize="32" type="int" group="float"/> + <reg name="fop" bitsize="32" type="int" group="float"/> +</feature> diff --git a/gdb-xml/i386-64bit-core.xml b/gdb-xml/i386-64bit-core.xml new file mode 100644 index 0000000..5088d84 --- /dev/null +++ b/gdb-xml/i386-64bit-core.xml @@ -0,0 +1,73 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.i386.core"> + <flags id="i386_eflags" size="4"> + <field name="CF" start="0" end="0"/> + <field name="" start="1" end="1"/> + <field name="PF" start="2" end="2"/> + <field name="AF" start="4" end="4"/> + <field name="ZF" start="6" end="6"/> + <field name="SF" start="7" end="7"/> + <field name="TF" start="8" end="8"/> + <field name="IF" start="9" end="9"/> + <field name="DF" start="10" end="10"/> + <field name="OF" start="11" end="11"/> + <field name="NT" start="14" end="14"/> + <field name="RF" start="16" end="16"/> + <field name="VM" start="17" end="17"/> + <field name="AC" start="18" end="18"/> + <field name="VIF" start="19" end="19"/> + <field name="VIP" start="20" end="20"/> + <field name="ID" start="21" end="21"/> + </flags> + + <reg name="rax" bitsize="64" type="int64"/> + <reg name="rbx" bitsize="64" type="int64"/> + <reg name="rcx" bitsize="64" type="int64"/> + <reg name="rdx" bitsize="64" type="int64"/> + <reg name="rsi" bitsize="64" type="int64"/> + <reg name="rdi" bitsize="64" type="int64"/> + <reg name="rbp" bitsize="64" type="data_ptr"/> + <reg name="rsp" bitsize="64" type="data_ptr"/> + <reg name="r8" bitsize="64" type="int64"/> + <reg name="r9" bitsize="64" type="int64"/> + <reg name="r10" bitsize="64" type="int64"/> + <reg name="r11" bitsize="64" type="int64"/> + <reg name="r12" bitsize="64" type="int64"/> + <reg name="r13" bitsize="64" type="int64"/> + <reg name="r14" bitsize="64" type="int64"/> + <reg name="r15" bitsize="64" type="int64"/> + + <reg name="rip" bitsize="64" type="code_ptr"/> + <reg name="eflags" bitsize="32" type="i386_eflags"/> + <reg name="cs" bitsize="32" type="int32"/> + <reg name="ss" bitsize="32" type="int32"/> + <reg name="ds" bitsize="32" type="int32"/> + <reg name="es" bitsize="32" type="int32"/> + <reg name="fs" bitsize="32" type="int32"/> + <reg name="gs" bitsize="32" type="int32"/> + + <reg name="st0" bitsize="80" type="i387_ext"/> + <reg name="st1" bitsize="80" type="i387_ext"/> + <reg name="st2" bitsize="80" type="i387_ext"/> + <reg name="st3" bitsize="80" type="i387_ext"/> + <reg name="st4" bitsize="80" type="i387_ext"/> + <reg name="st5" bitsize="80" type="i387_ext"/> + <reg name="st6" bitsize="80" type="i387_ext"/> + <reg name="st7" bitsize="80" type="i387_ext"/> + + <reg name="fctrl" bitsize="32" type="int" group="float"/> + <reg name="fstat" bitsize="32" type="int" group="float"/> + <reg name="ftag" bitsize="32" type="int" group="float"/> + <reg name="fiseg" bitsize="32" type="int" group="float"/> + <reg name="fioff" bitsize="32" type="int" group="float"/> + <reg name="foseg" bitsize="32" type="int" group="float"/> + <reg name="fooff" bitsize="32" type="int" group="float"/> + <reg name="fop" bitsize="32" type="int" group="float"/> +</feature> @@ -286,6 +286,8 @@ enum RSState { RS_INACTIVE, RS_IDLE, RS_GETLINE, + RS_GETLINE_ESC, + RS_GETLINE_RLE, RS_CHKSUM1, RS_CHKSUM2, }; @@ -296,7 +298,8 @@ typedef struct GDBState { enum RSState state; /* parsing state */ char line_buf[MAX_PACKET_LENGTH]; int line_buf_index; - int line_csum; + int line_sum; /* running checksum */ + int line_csum; /* checksum at the end of the packet */ uint8_t last_packet[MAX_PACKET_LENGTH + 4]; int last_packet_len; int signal; @@ -1508,7 +1511,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) static void gdb_read_byte(GDBState *s, int ch) { - int i, csum; uint8_t reply; #ifndef CONFIG_USER_ONLY @@ -1542,35 +1544,123 @@ static void gdb_read_byte(GDBState *s, int ch) switch(s->state) { case RS_IDLE: if (ch == '$') { + /* start of command packet */ s->line_buf_index = 0; + s->line_sum = 0; s->state = RS_GETLINE; + } else { +#ifdef DEBUG_GDB + printf("gdbstub received garbage between packets: 0x%x\n", ch); +#endif } break; case RS_GETLINE: + if (ch == '}') { + /* start escape sequence */ + s->state = RS_GETLINE_ESC; + s->line_sum += ch; + } else if (ch == '*') { + /* start run length encoding sequence */ + s->state = RS_GETLINE_RLE; + s->line_sum += ch; + } else if (ch == '#') { + /* end of command, start of checksum*/ + s->state = RS_CHKSUM1; + } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { +#ifdef DEBUG_GDB + printf("gdbstub command buffer overrun, dropping command\n"); +#endif + s->state = RS_IDLE; + } else { + /* unescaped command character */ + s->line_buf[s->line_buf_index++] = ch; + s->line_sum += ch; + } + break; + case RS_GETLINE_ESC: if (ch == '#') { - s->state = RS_CHKSUM1; + /* unexpected end of command in escape sequence */ + s->state = RS_CHKSUM1; } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { + /* command buffer overrun */ +#ifdef DEBUG_GDB + printf("gdbstub command buffer overrun, dropping command\n"); +#endif s->state = RS_IDLE; } else { - s->line_buf[s->line_buf_index++] = ch; + /* parse escaped character and leave escape state */ + s->line_buf[s->line_buf_index++] = ch ^ 0x20; + s->line_sum += ch; + s->state = RS_GETLINE; + } + break; + case RS_GETLINE_RLE: + if (ch < ' ') { + /* invalid RLE count encoding */ +#ifdef DEBUG_GDB + printf("gdbstub got invalid RLE count: 0x%x\n", ch); +#endif + s->state = RS_GETLINE; + } else { + /* decode repeat length */ + int repeat = (unsigned char)ch - ' ' + 3; + if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) { + /* that many repeats would overrun the command buffer */ +#ifdef DEBUG_GDB + printf("gdbstub command buffer overrun," + " dropping command\n"); +#endif + s->state = RS_IDLE; + } else if (s->line_buf_index < 1) { + /* got a repeat but we have nothing to repeat */ +#ifdef DEBUG_GDB + printf("gdbstub got invalid RLE sequence\n"); +#endif + s->state = RS_GETLINE; + } else { + /* repeat the last character */ + memset(s->line_buf + s->line_buf_index, + s->line_buf[s->line_buf_index - 1], repeat); + s->line_buf_index += repeat; + s->line_sum += ch; + s->state = RS_GETLINE; + } } break; case RS_CHKSUM1: + /* get high hex digit of checksum */ + if (!isxdigit(ch)) { +#ifdef DEBUG_GDB + printf("gdbstub got invalid command checksum digit\n"); +#endif + s->state = RS_GETLINE; + break; + } s->line_buf[s->line_buf_index] = '\0'; s->line_csum = fromhex(ch) << 4; s->state = RS_CHKSUM2; break; case RS_CHKSUM2: - s->line_csum |= fromhex(ch); - csum = 0; - for(i = 0; i < s->line_buf_index; i++) { - csum += s->line_buf[i]; + /* get low hex digit of checksum */ + if (!isxdigit(ch)) { +#ifdef DEBUG_GDB + printf("gdbstub got invalid command checksum digit\n"); +#endif + s->state = RS_GETLINE; + break; } - if (s->line_csum != (csum & 0xff)) { + s->line_csum |= fromhex(ch); + + if (s->line_csum != (s->line_sum & 0xff)) { + /* send NAK reply */ reply = '-'; put_buffer(s, &reply, 1); +#ifdef DEBUG_GDB + printf("gdbstub got command packet with incorrect checksum\n"); +#endif s->state = RS_IDLE; } else { + /* send ACK reply */ reply = '+'; put_buffer(s, &reply, 1); s->state = gdb_handle_packet(s, s->line_buf); @@ -1611,7 +1701,7 @@ void gdb_exit(CPUArchState *env, int code) #ifndef CONFIG_USER_ONLY qemu_chr_fe_deinit(&s->chr); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); #endif } @@ -1912,7 +2002,7 @@ int gdbserver_start(const char *device) monitor_init(mon_chr, 0); } else { if (qemu_chr_fe_get_driver(&s->chr)) { - qemu_chr_delete(qemu_chr_fe_get_driver(&s->chr)); + object_unparent(OBJECT(qemu_chr_fe_get_driver(&s->chr))); } mon_chr = s->mon_chr; memset(s, 0, sizeof(GDBState)); @@ -19,6 +19,7 @@ #include "net/eth.h" #include "sysemu/char.h" #include "sysemu/block-backend.h" +#include "sysemu/sysemu.h" #include "qemu/config-file.h" #include "qemu/option.h" #include "qemu/timer.h" @@ -1268,6 +1269,179 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &err); } +void hmp_loadvm(Monitor *mon, const QDict *qdict) +{ + int saved_vm_running = runstate_is_running(); + const char *name = qdict_get_str(qdict, "name"); + + vm_stop(RUN_STATE_RESTORE_VM); + + if (load_vmstate(name) == 0 && saved_vm_running) { + vm_start(); + } +} + +void hmp_savevm(Monitor *mon, const QDict *qdict) +{ + save_vmstate(qdict_get_try_str(qdict, "name")); +} + +void hmp_delvm(Monitor *mon, const QDict *qdict) +{ + BlockDriverState *bs; + Error *err; + const char *name = qdict_get_str(qdict, "name"); + + if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) { + error_reportf_err(err, + "Error while deleting snapshot on device '%s': ", + bdrv_get_device_name(bs)); + } +} + +void hmp_info_snapshots(Monitor *mon, const QDict *qdict) +{ + BlockDriverState *bs, *bs1; + BdrvNextIterator it1; + QEMUSnapshotInfo *sn_tab, *sn; + bool no_snapshot = true; + int nb_sns, i; + int total; + int *global_snapshots; + AioContext *aio_context; + + typedef struct SnapshotEntry { + QEMUSnapshotInfo sn; + QTAILQ_ENTRY(SnapshotEntry) next; + } SnapshotEntry; + + typedef struct ImageEntry { + const char *imagename; + QTAILQ_ENTRY(ImageEntry) next; + QTAILQ_HEAD(, SnapshotEntry) snapshots; + } ImageEntry; + + QTAILQ_HEAD(, ImageEntry) image_list = + QTAILQ_HEAD_INITIALIZER(image_list); + + ImageEntry *image_entry, *next_ie; + SnapshotEntry *snapshot_entry; + + bs = bdrv_all_find_vmstate_bs(); + if (!bs) { + monitor_printf(mon, "No available block device supports snapshots\n"); + return; + } + aio_context = bdrv_get_aio_context(bs); + + aio_context_acquire(aio_context); + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + aio_context_release(aio_context); + + if (nb_sns < 0) { + monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns); + return; + } + + for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) { + int bs1_nb_sns = 0; + ImageEntry *ie; + SnapshotEntry *se; + AioContext *ctx = bdrv_get_aio_context(bs1); + + aio_context_acquire(ctx); + if (bdrv_can_snapshot(bs1)) { + sn = NULL; + bs1_nb_sns = bdrv_snapshot_list(bs1, &sn); + if (bs1_nb_sns > 0) { + no_snapshot = false; + ie = g_new0(ImageEntry, 1); + ie->imagename = bdrv_get_device_name(bs1); + QTAILQ_INIT(&ie->snapshots); + QTAILQ_INSERT_TAIL(&image_list, ie, next); + for (i = 0; i < bs1_nb_sns; i++) { + se = g_new0(SnapshotEntry, 1); + se->sn = sn[i]; + QTAILQ_INSERT_TAIL(&ie->snapshots, se, next); + } + } + g_free(sn); + } + aio_context_release(ctx); + } + + if (no_snapshot) { + monitor_printf(mon, "There is no snapshot available.\n"); + return; + } + + global_snapshots = g_new0(int, nb_sns); + total = 0; + for (i = 0; i < nb_sns; i++) { + SnapshotEntry *next_sn; + if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) { + global_snapshots[total] = i; + total++; + QTAILQ_FOREACH(image_entry, &image_list, next) { + QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, + next, next_sn) { + if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) { + QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry, + next); + g_free(snapshot_entry); + } + } + } + } + } + + monitor_printf(mon, "List of snapshots present on all disks:\n"); + + if (total > 0) { + bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL); + monitor_printf(mon, "\n"); + for (i = 0; i < total; i++) { + sn = &sn_tab[global_snapshots[i]]; + /* The ID is not guaranteed to be the same on all images, so + * overwrite it. + */ + pstrcpy(sn->id_str, sizeof(sn->id_str), "--"); + bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn); + monitor_printf(mon, "\n"); + } + } else { + monitor_printf(mon, "None\n"); + } + + QTAILQ_FOREACH(image_entry, &image_list, next) { + if (QTAILQ_EMPTY(&image_entry->snapshots)) { + continue; + } + monitor_printf(mon, + "\nList of partial (non-loadable) snapshots on '%s':\n", + image_entry->imagename); + bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL); + monitor_printf(mon, "\n"); + QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) { + bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, + &snapshot_entry->sn); + monitor_printf(mon, "\n"); + } + } + + QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) { + SnapshotEntry *next_sn; + QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next, + next_sn) { + g_free(snapshot_entry); + } + g_free(image_entry); + } + g_free(sn_tab); + g_free(global_snapshots); + +} + void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) { qmp_migrate_cancel(NULL); @@ -63,6 +63,10 @@ void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict); void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict); void hmp_drive_mirror(Monitor *mon, const QDict *qdict); void hmp_drive_backup(Monitor *mon, const QDict *qdict); +void hmp_loadvm(Monitor *mon, const QDict *qdict); +void hmp_savevm(Monitor *mon, const QDict *qdict); +void hmp_delvm(Monitor *mon, const QDict *qdict); +void hmp_info_snapshots(Monitor *mon, const QDict *qdict); void hmp_migrate_cancel(Monitor *mon, const QDict *qdict); void hmp_migrate_incoming(Monitor *mon, const QDict *qdict); void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict); diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs index 7ce85a2..bb6f07a 100644 --- a/hw/audio/Makefile.objs +++ b/hw/audio/Makefile.objs @@ -14,5 +14,3 @@ common-obj-$(CONFIG_PL041) += pl041.o lm4549.o common-obj-$(CONFIG_CS4231) += cs4231.o common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o - -$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 7836446..09b8248 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -33,11 +33,7 @@ #define ADLIB_KILL_TIMERS 1 -#ifdef HAS_YMF262 -#define ADLIB_DESC "Yamaha YMF262 (OPL3)" -#else #define ADLIB_DESC "Yamaha YM3812 (OPL2)" -#endif #ifdef DEBUG #include "qemu/timer.h" @@ -50,14 +46,8 @@ #define ldebug(...) #endif -#ifdef HAS_YMF262 -#include "ymf262.h" -void YMF262UpdateOneQEMU (int which, INT16 *dst, int length); -#define SHIFT 2 -#else #include "fmopl.h" #define SHIFT 1 -#endif #define TYPE_ADLIB "adlib" #define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB) @@ -80,9 +70,7 @@ typedef struct { SWVoiceOut *voice; int left, pos, samples; QEMUAudioTimeStamp ats; -#ifndef HAS_YMF262 FM_OPL *opl; -#endif PortioList port_list; } AdlibState; @@ -90,11 +78,7 @@ static AdlibState *glob_adlib; static void adlib_stop_opl_timer (AdlibState *s, size_t n) { -#ifdef HAS_YMF262 - YMF262TimerOver (0, n); -#else OPLTimerOver (s->opl, n); -#endif s->ticking[n] = 0; } @@ -131,11 +115,7 @@ static void adlib_write(void *opaque, uint32_t nport, uint32_t val) adlib_kill_timers (s); -#ifdef HAS_YMF262 - YMF262Write (0, a, val); -#else OPLWrite (s->opl, a, val); -#endif } static uint32_t adlib_read(void *opaque, uint32_t nport) @@ -145,12 +125,8 @@ static uint32_t adlib_read(void *opaque, uint32_t nport) int a = nport & 3; adlib_kill_timers (s); - -#ifdef HAS_YMF262 - data = YMF262Read (0, a); -#else data = OPLRead (s->opl, a); -#endif + return data; } @@ -240,11 +216,7 @@ static void adlib_callback (void *opaque, int free) return; } -#ifdef HAS_YMF262 - YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples); -#else YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples); -#endif while (samples) { written = write_audio (s, samples); @@ -263,14 +235,10 @@ static void adlib_callback (void *opaque, int free) static void Adlib_fini (AdlibState *s) { -#ifdef HAS_YMF262 - YMF262Shutdown (); -#else if (s->opl) { OPLDestroy (s->opl); s->opl = NULL; } -#endif g_free(s->mixbuf); @@ -297,17 +265,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp) } glob_adlib = s; -#ifdef HAS_YMF262 - if (YMF262Init (1, 14318180, s->freq)) { - error_setg (errp, "YMF262Init %d failed", s->freq); - return; - } - else { - YMF262SetTimerHandler (0, timer_handler, 0); - s->enabled = 1; - } -#else - s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq); + s->opl = OPLCreate (3579545, s->freq); if (!s->opl) { error_setg (errp, "OPLCreate %d failed", s->freq); return; @@ -316,7 +274,6 @@ static void adlib_realizefn (DeviceState *dev, Error **errp) OPLSetTimerHandler (s->opl, timer_handler, 0); s->enabled = 1; } -#endif as.freq = s->freq; as.nchannels = SHIFT; diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c index 731110f..202f752 100644 --- a/hw/audio/fmopl.c +++ b/hw/audio/fmopl.c @@ -30,21 +30,15 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#define HAS_YM3812 1 - #include "qemu/osdep.h" #include <math.h> //#include "driver.h" /* use M.A.M.E. */ #include "fmopl.h" - +#include "qemu/osdep.h" #ifndef PI #define PI 3.14159265358979323846 #endif -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - /* -------------------- for debug --------------------- */ /* #define OPL_OUTPUT_LOG */ #ifdef OPL_OUTPUT_LOG @@ -124,7 +118,7 @@ static const int slot_array[32]= /* key scale level */ /* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */ #define DV (EG_STEP/2) -static const UINT32 KSL_TABLE[8*16]= +static const uint32_t KSL_TABLE[8*16]= { /* OCT 0 */ 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, @@ -172,7 +166,7 @@ static const UINT32 KSL_TABLE[8*16]= /* sustain lebel table (3db per step) */ /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ #define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST -static const INT32 SL_TABLE[16]={ +static const int32_t SL_TABLE[16]={ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) }; @@ -182,22 +176,22 @@ static const INT32 SL_TABLE[16]={ /* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */ /* TL_TABLE[ 0 to TL_MAX ] : plus section */ /* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */ -static INT32 *TL_TABLE; +static int32_t *TL_TABLE; /* pointers to TL_TABLE with sinwave output offset */ -static INT32 **SIN_TABLE; +static int32_t **SIN_TABLE; /* LFO table */ -static INT32 *AMS_TABLE; -static INT32 *VIB_TABLE; +static int32_t *AMS_TABLE; +static int32_t *VIB_TABLE; /* envelope output curve table */ /* attack + decay + OFF */ -static INT32 ENV_CURVE[2*EG_ENT+1]; +static int32_t ENV_CURVE[2*EG_ENT+1]; /* multiple table */ #define ML 2 -static const UINT32 MUL_TABLE[16]= { +static const uint32_t MUL_TABLE[16]= { /* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */ 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML, 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML @@ -205,7 +199,7 @@ static const UINT32 MUL_TABLE[16]= { #undef ML /* dummy attack / decay rate ( when rate == 0 ) */ -static INT32 RATE_0[16]= +static int32_t RATE_0[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* -------------------- static state --------------------- */ @@ -221,14 +215,14 @@ static OPL_CH *S_CH; static OPL_CH *E_CH; static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2; -static INT32 outd[1]; -static INT32 ams; -static INT32 vib; -static INT32 *ams_table; -static INT32 *vib_table; -static INT32 amsIncr; -static INT32 vibIncr; -static INT32 feedback2; /* connect for SLOT 2 */ +static int32_t outd[1]; +static int32_t ams; +static int32_t vib; +static int32_t *ams_table; +static int32_t *vib_table; +static int32_t amsIncr; +static int32_t vibIncr; +static int32_t feedback2; /* connect for SLOT 2 */ /* log output level */ #define LOG_ERR 3 /* ERROR */ @@ -262,8 +256,6 @@ static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag) if(OPL->status & OPL->statusmask) { /* IRQ on */ OPL->status |= 0x80; - /* callback user interrupt handler (IRQ is OFF to ON) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); } } } @@ -278,8 +270,6 @@ static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag) if (!(OPL->status & OPL->statusmask) ) { OPL->status &= 0x7f; - /* callback user interrupt handler (IRQ is ON to OFF) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); } } } @@ -321,7 +311,7 @@ static inline void OPL_KEYOFF(OPL_SLOT *SLOT) /* ---------- calcrate Envelope Generator & Phase Generator ---------- */ /* return : envelope output */ -static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) +static inline uint32_t OPL_CALC_SLOT( OPL_SLOT *SLOT ) { /* calcrate envelope generator */ if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) @@ -361,7 +351,7 @@ static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) /* set algorithm connection */ static void set_algorithm( OPL_CH *CH) { - INT32 *carrier = &outd[0]; + int32_t *carrier = &outd[0]; CH->connect1 = CH->CON ? carrier : &feedback2; CH->connect2 = carrier; } @@ -453,7 +443,7 @@ static inline void set_sl_rr(FM_OPL *OPL,int slot,int v) /* ---------- calcrate one of channel ---------- */ static inline void OPL_CALC_CH( OPL_CH *CH ) { - UINT32 env_out; + uint32_t env_out; OPL_SLOT *SLOT; feedback2 = 0; @@ -498,9 +488,9 @@ static inline void OPL_CALC_CH( OPL_CH *CH ) #define WHITE_NOISE_db 6.0 static inline void OPL_CALC_RH( OPL_CH *CH ) { - UINT32 env_tam,env_sd,env_top,env_hh; + uint32_t env_tam,env_sd,env_top,env_hh; int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); - INT32 tone8; + int32_t tone8; OPL_SLOT *SLOT; int env_out; @@ -618,20 +608,20 @@ static int OPLOpenTable( void ) double pom; /* allocate dynamic tables */ - if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL) + if( (TL_TABLE = malloc(TL_MAX*2*sizeof(int32_t))) == NULL) return 0; - if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) + if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(int32_t *))) == NULL) { free(TL_TABLE); return 0; } - if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) + if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(int32_t))) == NULL) { free(TL_TABLE); free(SIN_TABLE); return 0; } - if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL) + if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(int32_t))) == NULL) { free(TL_TABLE); free(SIN_TABLE); @@ -763,18 +753,15 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) { case 0x01: /* wave selector enable */ - if(OPL->type&OPL_TYPE_WAVESEL) + OPL->wavesel = v&0x20; + if(!OPL->wavesel) { - OPL->wavesel = v&0x20; - if(!OPL->wavesel) + /* preset compatible mode */ + int c; + for(c=0;c<OPL->max_ch;c++) { - /* preset compatible mode */ - int c; - for(c=0;c<OPL->max_ch;c++) - { - OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; - OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; - } + OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; + OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; } } return; @@ -791,8 +778,8 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) } else { /* set IRQ mask ,timer enable*/ - UINT8 st1 = v&1; - UINT8 st2 = (v>>1)&1; + uint8_t st1 = v&1; + uint8_t st2 = (v>>1)&1; /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ OPL_STATUS_RESET(OPL,v&0x78); OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); @@ -812,57 +799,6 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) } } return; -#if BUILD_Y8950 - case 0x06: /* Key Board OUT */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_w) - OPL->keyboardhandler_w(OPL->keyboard_param,v); - else - LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); - } - return; - case 0x07: /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - return; - case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ - OPL->mode = v; - v&=0x1f; /* for DELTA-T unit */ - case 0x09: /* START ADD */ - case 0x0a: - case 0x0b: /* STOP ADD */ - case 0x0c: - case 0x0d: /* PRESCALE */ - case 0x0e: - case 0x0f: /* ADPCM data */ - case 0x10: /* DELTA-N */ - case 0x11: /* DELTA-N */ - case 0x12: /* EG-CTRL */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - return; -#if 0 - case 0x15: /* DAC data */ - case 0x16: - case 0x17: /* SHIFT */ - return; - case 0x18: /* I/O CTRL (Direction) */ - if(OPL->type&OPL_TYPE_IO) - OPL->portDirection = v&0x0f; - return; - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - OPL->portLatch = v; - if(OPL->porthandler_w) - OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); - } - return; - case 0x1a: /* PCM data */ - return; -#endif -#endif } break; case 0x20: /* am,vib,ksr,eg type,mul */ @@ -891,7 +827,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) case 0xbd: /* amsep,vibdep,r,bd,sd,tom,tc,hh */ { - UINT8 rkey = OPL->rhythm^v; + uint8_t rkey = OPL->rhythm^v; OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; OPL->rhythm = v&0x3f; @@ -1032,20 +968,19 @@ static void OPL_UnLockTable(void) OPLCloseTable(); } -#if (BUILD_YM3812 || BUILD_YM3526) /*******************************************************************************/ /* YM3812 local section */ /*******************************************************************************/ /* ---------- update one of chip ----------- */ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) +void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length) { int i; int data; - OPLSAMPLE *buf = buffer; - UINT32 amsCnt = OPL->amsCnt; - UINT32 vibCnt = OPL->vibCnt; - UINT8 rhythm = OPL->rhythm&0x20; + int16_t *buf = buffer; + uint32_t amsCnt = OPL->amsCnt; + uint32_t vibCnt = OPL->vibCnt; + uint8_t rhythm = OPL->rhythm&0x20; OPL_CH *CH,*R_CH; if( (void *)OPL != cur_chip ){ @@ -1095,72 +1030,9 @@ void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) } #endif } -#endif /* (BUILD_YM3812 || BUILD_YM3526) */ - -#if BUILD_Y8950 - -void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) -{ - int i; - int data; - OPLSAMPLE *buf = buffer; - UINT32 amsCnt = OPL->amsCnt; - UINT32 vibCnt = OPL->vibCnt; - UINT8 rhythm = OPL->rhythm&0x20; - OPL_CH *CH,*R_CH; - YM_DELTAT *DELTAT = OPL->deltat; - - /* setup DELTA-T unit */ - YM_DELTAT_DECODE_PRESET(DELTAT); - - if( (void *)OPL != cur_chip ){ - cur_chip = (void *)OPL; - /* channel pointers */ - S_CH = OPL->P_CH; - E_CH = &S_CH[9]; - /* rhythm slot */ - SLOT7_1 = &S_CH[7].SLOT[SLOT1]; - SLOT7_2 = &S_CH[7].SLOT[SLOT2]; - SLOT8_1 = &S_CH[8].SLOT[SLOT1]; - SLOT8_2 = &S_CH[8].SLOT[SLOT2]; - /* LFO state */ - amsIncr = OPL->amsIncr; - vibIncr = OPL->vibIncr; - ams_table = OPL->ams_table; - vib_table = OPL->vib_table; - } - R_CH = rhythm ? &S_CH[6] : E_CH; - for( i=0; i < length ; i++ ) - { - /* channel A channel B channel C */ - /* LFO */ - ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; - vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; - outd[0] = 0; - /* deltaT ADPCM */ - if( DELTAT->portstate ) - YM_DELTAT_ADPCM_CALC(DELTAT); - /* FM part */ - for(CH=S_CH ; CH < R_CH ; CH++) - OPL_CALC_CH(CH); - /* Rythn part */ - if(rhythm) - OPL_CALC_RH(S_CH); - /* limit check */ - data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); - /* store to sound buffer */ - buf[i] = data >> OPL_OUTSB; - } - OPL->amsCnt = amsCnt; - OPL->vibCnt = vibCnt; - /* deltaT START flag */ - if( !DELTAT->portstate ) - OPL->status &= 0xfe; -} -#endif /* ---------- reset one of chip ---------- */ -void OPLResetChip(FM_OPL *OPL) +static void OPLResetChip(FM_OPL *OPL) { int c,s; int i; @@ -1189,23 +1061,11 @@ void OPLResetChip(FM_OPL *OPL) CH->SLOT[s].evs = 0; } } -#if BUILD_Y8950 - if(OPL->type&OPL_TYPE_ADPCM) - { - YM_DELTAT *DELTAT = OPL->deltat; - - DELTAT->freqbase = OPL->freqbase; - DELTAT->output_pointer = outd; - DELTAT->portshift = 5; - DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS; - YM_DELTAT_ADPCM_Reset(DELTAT,0); - } -#endif } /* ---------- Create one of vietual YM3812 ---------- */ /* 'rate' is sampling rate and 'bufsiz' is the size of the */ -FM_OPL *OPLCreate(int type, int clock, int rate) +FM_OPL *OPLCreate(int clock, int rate) { char *ptr; FM_OPL *OPL; @@ -1216,9 +1076,6 @@ FM_OPL *OPLCreate(int type, int clock, int rate) /* allocate OPL state space */ state_size = sizeof(FM_OPL); state_size += sizeof(OPL_CH)*max_ch; -#if BUILD_Y8950 - if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); -#endif /* allocate memory block */ ptr = malloc(state_size); if(ptr==NULL) return NULL; @@ -1226,11 +1083,7 @@ FM_OPL *OPLCreate(int type, int clock, int rate) memset(ptr,0,state_size); OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL); OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch; -#if BUILD_Y8950 - if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); -#endif /* set channel state pointer */ - OPL->type = type; OPL->clock = clock; OPL->rate = rate; OPL->max_ch = max_ch; @@ -1280,31 +1133,7 @@ void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOff OPL->TimerHandler = TimerHandler; OPL->TimerParam = channelOffset; } -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) -{ - OPL->IRQHandler = IRQHandler; - OPL->IRQParam = param; -} -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) -{ - OPL->UpdateHandler = UpdateHandler; - OPL->UpdateParam = param; -} -#if BUILD_Y8950 -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) -{ - OPL->porthandler_w = PortHandler_w; - OPL->porthandler_r = PortHandler_r; - OPL->port_param = param; -} -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) -{ - OPL->keyboardhandler_w = KeyboardHandler_w; - OPL->keyboardhandler_r = KeyboardHandler_r; - OPL->keyboard_param = param; -} -#endif /* ---------- YM3812 I/O interface ---------- */ int OPLWrite(FM_OPL *OPL,int a,int v) { @@ -1314,7 +1143,6 @@ int OPLWrite(FM_OPL *OPL,int a,int v) } else { /* data port */ - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); #ifdef OPL_OUTPUT_LOG if(opl_dbg_fp) { @@ -1338,28 +1166,12 @@ unsigned char OPLRead(FM_OPL *OPL,int a) switch(OPL->address) { case 0x05: /* KeyBoard IN */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_r) - return OPL->keyboardhandler_r(OPL->keyboard_param); - else { - LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); - } - } return 0; #if 0 case 0x0f: /* ADPCM-DATA */ return 0; #endif case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - if(OPL->porthandler_r) - return OPL->porthandler_r(OPL->port_param); - else { - LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); - } - } return 0; case 0x1a: /* PCM-DATA */ return 0; @@ -1380,7 +1192,6 @@ int OPLTimerOver(FM_OPL *OPL,int c) if( OPL->mode & 0x80 ) { /* CSM mode total level latch and auto key on */ int ch; - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); for(ch=0;ch<9;ch++) CSMKeyControll( &OPL->P_CH[ch] ); } diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h index fdda7f9..fc9f16b 100644 --- a/hw/audio/fmopl.h +++ b/hw/audio/fmopl.h @@ -1,174 +1,103 @@ #ifndef FMOPL_H #define FMOPL_H -/* --- select emulation chips --- */ -#define BUILD_YM3812 (HAS_YM3812) -//#define BUILD_YM3526 (HAS_YM3526) -//#define BUILD_Y8950 (HAS_Y8950) - -/* --- system optimize --- */ -/* select bit size of output : 8 or 16 */ -#define OPL_OUTPUT_BIT 16 - -/* compiler dependence */ -#ifndef OSD_CPU_H -#define OSD_CPU_H -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ -#endif - -#if (OPL_OUTPUT_BIT==16) -typedef INT16 OPLSAMPLE; -#endif -#if (OPL_OUTPUT_BIT==8) -typedef unsigned char OPLSAMPLE; -#endif - - -#if BUILD_Y8950 -#include "ymdeltat.h" -#endif +#include <stdint.h> typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); -typedef void (*OPL_IRQHANDLER)(int param,int irq); -typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); -typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); -typedef unsigned char (*OPL_PORTHANDLER_R)(int param); /* !!!!! here is private section , do not access there member direct !!!!! */ -#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ -#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ -#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ -#define OPL_TYPE_IO 0x08 /* I/O port */ - /* Saving is necessary for member of the 'R' mark for suspend/resume */ /* ---------- OPL one of slot ---------- */ typedef struct fm_opl_slot { - INT32 TL; /* total level :TL << 8 */ - INT32 TLL; /* adjusted now TL */ - UINT8 KSR; /* key scale rate :(shift down bit) */ - INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */ - INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */ - INT32 SL; /* sustin level :SL_TALBE[SL] */ - INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */ - UINT8 ksl; /* keyscale level :(shift down bits) */ - UINT8 ksr; /* key scale rate :kcode>>KSR */ - UINT32 mul; /* multiple :ML_TABLE[ML] */ - UINT32 Cnt; /* frequency count : */ - UINT32 Incr; /* frequency step : */ + int32_t TL; /* total level :TL << 8 */ + int32_t TLL; /* adjusted now TL */ + uint8_t KSR; /* key scale rate :(shift down bit) */ + int32_t *AR; /* attack rate :&AR_TABLE[AR<<2] */ + int32_t *DR; /* decay rate :&DR_TALBE[DR<<2] */ + int32_t SL; /* sustin level :SL_TALBE[SL] */ + int32_t *RR; /* release rate :&DR_TABLE[RR<<2] */ + uint8_t ksl; /* keyscale level :(shift down bits) */ + uint8_t ksr; /* key scale rate :kcode>>KSR */ + uint32_t mul; /* multiple :ML_TABLE[ML] */ + uint32_t Cnt; /* frequency count : */ + uint32_t Incr; /* frequency step : */ /* envelope generator state */ - UINT8 eg_typ; /* envelope type flag */ - UINT8 evm; /* envelope phase */ - INT32 evc; /* envelope counter */ - INT32 eve; /* envelope counter end point */ - INT32 evs; /* envelope counter step */ - INT32 evsa; /* envelope step for AR :AR[ksr] */ - INT32 evsd; /* envelope step for DR :DR[ksr] */ - INT32 evsr; /* envelope step for RR :RR[ksr] */ + uint8_t eg_typ; /* envelope type flag */ + uint8_t evm; /* envelope phase */ + int32_t evc; /* envelope counter */ + int32_t eve; /* envelope counter end point */ + int32_t evs; /* envelope counter step */ + int32_t evsa; /* envelope step for AR :AR[ksr] */ + int32_t evsd; /* envelope step for DR :DR[ksr] */ + int32_t evsr; /* envelope step for RR :RR[ksr] */ /* LFO */ - UINT8 ams; /* ams flag */ - UINT8 vib; /* vibrate flag */ + uint8_t ams; /* ams flag */ + uint8_t vib; /* vibrate flag */ /* wave selector */ - INT32 **wavetable; + int32_t **wavetable; }OPL_SLOT; /* ---------- OPL one of channel ---------- */ typedef struct fm_opl_channel { OPL_SLOT SLOT[2]; - UINT8 CON; /* connection type */ - UINT8 FB; /* feed back :(shift down bit) */ - INT32 *connect1; /* slot1 output pointer */ - INT32 *connect2; /* slot2 output pointer */ - INT32 op1_out[2]; /* slot1 output for selfeedback */ + uint8_t CON; /* connection type */ + uint8_t FB; /* feed back :(shift down bit) */ + int32_t *connect1; /* slot1 output pointer */ + int32_t *connect2; /* slot2 output pointer */ + int32_t op1_out[2]; /* slot1 output for selfeedback */ /* phase generator state */ - UINT32 block_fnum; /* block+fnum : */ - UINT8 kcode; /* key code : KeyScaleCode */ - UINT32 fc; /* Freq. Increment base */ - UINT32 ksl_base; /* KeyScaleLevel Base step */ - UINT8 keyon; /* key on/off flag */ + uint32_t block_fnum; /* block+fnum : */ + uint8_t kcode; /* key code : KeyScaleCode */ + uint32_t fc; /* Freq. Increment base */ + uint32_t ksl_base; /* KeyScaleLevel Base step */ + uint8_t keyon; /* key on/off flag */ } OPL_CH; /* OPL state */ typedef struct fm_opl_f { - UINT8 type; /* chip type */ int clock; /* master clock (Hz) */ int rate; /* sampling rate (Hz) */ double freqbase; /* frequency base */ double TimerBase; /* Timer base time (==sampling time) */ - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - UINT8 statusmask; /* status mask */ - UINT32 mode; /* Reg.08 : CSM , notesel,etc. */ + uint8_t address; /* address register */ + uint8_t status; /* status flag */ + uint8_t statusmask; /* status mask */ + uint32_t mode; /* Reg.08 : CSM , notesel,etc. */ /* Timer */ int T[2]; /* timer counter */ - UINT8 st[2]; /* timer enable */ + uint8_t st[2]; /* timer enable */ /* FM channel slots */ OPL_CH *P_CH; /* pointer of CH */ int max_ch; /* maximum channel */ /* Rhythm sention */ - UINT8 rhythm; /* Rhythm mode , key flag */ -#if BUILD_Y8950 - /* Delta-T ADPCM unit (Y8950) */ - YM_DELTAT *deltat; /* DELTA-T ADPCM */ -#endif - /* Keyboard / I/O interface unit (Y8950) */ - UINT8 portDirection; - UINT8 portLatch; - OPL_PORTHANDLER_R porthandler_r; - OPL_PORTHANDLER_W porthandler_w; - int port_param; - OPL_PORTHANDLER_R keyboardhandler_r; - OPL_PORTHANDLER_W keyboardhandler_w; - int keyboard_param; + uint8_t rhythm; /* Rhythm mode , key flag */ /* time tables */ - INT32 AR_TABLE[75]; /* atttack rate tables */ - INT32 DR_TABLE[75]; /* decay rate tables */ - UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */ + int32_t AR_TABLE[75]; /* atttack rate tables */ + int32_t DR_TABLE[75]; /* decay rate tables */ + uint32_t FN_TABLE[1024]; /* fnumber -> increment counter */ /* LFO */ - INT32 *ams_table; - INT32 *vib_table; - INT32 amsCnt; - INT32 amsIncr; - INT32 vibCnt; - INT32 vibIncr; + int32_t *ams_table; + int32_t *vib_table; + int32_t amsCnt; + int32_t amsIncr; + int32_t vibCnt; + int32_t vibIncr; /* wave selector enable flag */ - UINT8 wavesel; + uint8_t wavesel; /* external event callback handler */ OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ int TimerParam; /* TIMER parameter */ - OPL_IRQHANDLER IRQHandler; /* IRQ handler */ - int IRQParam; /* IRQ parameter */ - OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ - int UpdateParam; /* stream update parameter */ } FM_OPL; /* ---------- Generic interface section ---------- */ -#define OPL_TYPE_YM3526 (0) -#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) -#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) - -FM_OPL *OPLCreate(int type, int clock, int rate); +FM_OPL *OPLCreate(int clock, int rate); void OPLDestroy(FM_OPL *OPL); void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); -/* Y8950 port handlers */ -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); -void OPLResetChip(FM_OPL *OPL); int OPLWrite(FM_OPL *OPL,int a,int v); unsigned char OPLRead(FM_OPL *OPL,int a); int OPLTimerOver(FM_OPL *OPL,int c); -/* YM3626/YM3812 local section */ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); - -void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); - +void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length); #endif diff --git a/hw/audio/gus.c b/hw/audio/gus.c index 3d08a65..ec103a4 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -53,7 +53,7 @@ typedef struct GUSState { uint32_t freq; uint32_t port; int pos, left, shift, irqs; - GUSsample *mixbuf; + int16_t *mixbuf; uint8_t himem[1024 * 1024 + 32 + 4096]; int samples; SWVoiceOut *voice; diff --git a/hw/audio/gusemu.h b/hw/audio/gusemu.h index 9aec7bf..ab591ee 100644 --- a/hw/audio/gusemu.h +++ b/hw/audio/gusemu.h @@ -25,26 +25,10 @@ #ifndef GUSEMU_H #define GUSEMU_H -/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */ - -#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */ - typedef unsigned char GUSbyte; - typedef unsigned short GUSword; - typedef unsigned int GUSdword; - typedef signed char GUSchar; - typedef signed short GUSsample; -#else - typedef int8_t GUSchar; - typedef uint8_t GUSbyte; - typedef uint16_t GUSword; - typedef uint32_t GUSdword; - typedef int16_t GUSsample; -#endif - typedef struct _GUSEmuState { - GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */ - GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */ + uint8_t *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */ + uint8_t *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */ uint32_t gusirq; uint32_t gusdma; unsigned int timer1fraction; @@ -92,7 +76,7 @@ void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count /* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */ /* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */ -void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos); +void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, int16_t *bufferpos); /* recommended range: 10 < numsamples < 100 */ /* lower values may result in increased rounding error, higher values often cause audible timing delays */ diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c index 973d6b9..1150fc4 100644 --- a/hw/audio/gusemu_hal.c +++ b/hw/audio/gusemu_hal.c @@ -31,15 +31,15 @@ #include "gusemu.h" #define GUSregb(position) (* (gusptr+(position))) -#define GUSregw(position) (*(GUSword *) (gusptr+(position))) -#define GUSregd(position) (*(GUSdword *)(gusptr+(position))) +#define GUSregw(position) (*(uint16_t *) (gusptr+(position))) +#define GUSregd(position) (*(uint16_t *)(gusptr+(position))) /* size given in bytes */ unsigned int gus_read(GUSEmuState * state, int port, int size) { int value_read = 0; - GUSbyte *gusptr; + uint8_t *gusptr; gusptr = state->gusdatapos; GUSregd(portaccesses)++; @@ -125,7 +125,7 @@ unsigned int gus_read(GUSEmuState * state, int port, int size) if (!GUSregb(IRQStatReg2x6)) GUS_irqclear(state, state->gusirq); } - return (GUSbyte) value_read; + return (uint8_t) value_read; /* DramDMAmemPosReg */ /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/ /* 43h+44h write only */ @@ -173,12 +173,12 @@ unsigned int gus_read(GUSEmuState * state, int port, int size) value_read = value_read >> 8; value_read &= 0xff; } - return (GUSword) value_read; + return (uint16_t) value_read; /* case 0x306: */ /* Mixer/Version info */ /* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */ case 0x307: /* DRAMaccess */ { - GUSbyte *adr; + uint8_t *adr; adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff); return *adr; } @@ -189,14 +189,14 @@ unsigned int gus_read(GUSEmuState * state, int port, int size) void gus_write(GUSEmuState * state, int port, int size, unsigned int data) { - GUSbyte *gusptr; + uint8_t *gusptr; gusptr = state->gusdatapos; GUSregd(portaccesses)++; switch (port & 0xff0f) { case 0x200: /* MixerCtrlReg */ - GUSregb(MixerCtrlReg2x0) = (GUSbyte) data; + GUSregb(MixerCtrlReg2x0) = (uint8_t) data; break; case 0x206: /* IRQstatReg / SB2x6IRQ */ if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */ @@ -208,7 +208,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) break; case 0x308: /* AdLib 388h */ case 0x208: /* AdLibCommandReg */ - GUSregb(AdLibCommand2xA) = (GUSbyte) data; + GUSregb(AdLibCommand2xA) = (uint8_t) data; break; case 0x309: /* AdLib 389h */ case 0x209: /* AdLibDataReg */ @@ -217,11 +217,11 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) if (data & 0x80) GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */ else - GUSregb(TimerDataReg2x9) = (GUSbyte) data; + GUSregb(TimerDataReg2x9) = (uint8_t) data; } else { - GUSregb(AdLibData2x9) = (GUSbyte) data; + GUSregb(AdLibData2x9) = (uint8_t) data; if (GUSregb(GUS45TimerCtrl) & 0x02) { GUSregb(TimerStatus2x8) |= 0x01; @@ -231,16 +231,16 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) } break; case 0x20A: - GUSregb(AdLibStatus2x8) = (GUSbyte) data; + GUSregb(AdLibStatus2x8) = (uint8_t) data; break; /* AdLibStatus2x8 */ case 0x20B: /* GUS hidden registers */ switch (GUSregb(RegCtrl_2xF) & 0x7) { case 0: if (GUSregb(MixerCtrlReg2x0) & 0x40) - GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */ + GUSregb(IRQ_2xB) = (uint8_t) data; /* control register select bit */ else - GUSregb(DMA_2xB) = (GUSbyte) data; + GUSregb(DMA_2xB) = (uint8_t) data; break; /* case 1-4: general purpose emulation regs */ case 5: /* clear stat reg 2xF */ @@ -249,7 +249,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) GUS_irqclear(state, state->gusirq); break; case 6: /* Jumper reg (Joystick/MIDI enable) */ - GUSregb(Jumper_2xB) = (GUSbyte) data; + GUSregb(Jumper_2xB) = (uint8_t) data; break; default:; } @@ -262,20 +262,20 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) GUS_irqrequest(state, state->gusirq, 1); } case 0x20D: /* SB2xCd no IRQ */ - GUSregb(SB2xCd) = (GUSbyte) data; + GUSregb(SB2xCd) = (uint8_t) data; break; case 0x20E: /* SB2xE */ - GUSregb(SB2xE) = (GUSbyte) data; + GUSregb(SB2xE) = (uint8_t) data; break; case 0x20F: - GUSregb(RegCtrl_2xF) = (GUSbyte) data; + GUSregb(RegCtrl_2xF) = (uint8_t) data; break; /* CtrlReg2xF */ case 0x302: /* VoiceSelReg */ - GUSregb(VoiceSelReg3x2) = (GUSbyte) data; + GUSregb(VoiceSelReg3x2) = (uint8_t) data; break; case 0x303: /* FunkSelReg */ - GUSregb(FunkSelReg3x3) = (GUSbyte) data; - if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */ + GUSregb(FunkSelReg3x3) = (uint8_t) data; + if ((uint8_t) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */ { int voice; if (GUSregd(voicewavetableirq)) /* WavetableIRQ */ @@ -318,15 +318,15 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) case 0x304: case 0x305: { - GUSword writedata = (GUSword) data; - GUSword readmask = 0x0000; + uint16_t writedata = (uint16_t) data; + uint16_t readmask = 0x0000; if (size == 1) { readmask = 0xff00; writedata &= 0xff; if ((port & 0xff0f) == 0x305) { - writedata = (GUSword) (writedata << 8); + writedata = (uint16_t) (writedata << 8); readmask = 0x00ff; } } @@ -353,17 +353,17 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) break; /* reset flag active? */ offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f); offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */ - GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata); + GUSregw(offset) = (uint16_t) ((GUSregw(offset) & readmask) | writedata); } break; /* voice unspecific functions */ case 0x0e: /* NumVoices */ - GUSregb(NumVoices) = (GUSbyte) data; + GUSregb(NumVoices) = (uint8_t) data; break; /* case 0x0f: */ /* read only */ /* common functions */ case 0x41: /* DramDMAContrReg */ - GUSregb(GUS41DMACtrl) = (GUSbyte) data; + GUSregb(GUS41DMACtrl) = (uint8_t) data; if (data & 0x01) GUS_dmarequest(state); break; @@ -380,7 +380,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16); break; case 0x45: /* TCtrlReg */ - GUSregb(GUS45TimerCtrl) = (GUSbyte) data; + GUSregb(GUS45TimerCtrl) = (uint8_t) data; if (!(data & 0x20)) GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */ if (!(data & 0x02)) @@ -434,18 +434,18 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) GUS_irqclear(state, state->gusirq); break; case 0x46: /* Counter1 */ - GUSregb(GUS46Counter1) = (GUSbyte) data; + GUSregb(GUS46Counter1) = (uint8_t) data; break; case 0x47: /* Counter2 */ - GUSregb(GUS47Counter2) = (GUSbyte) data; + GUSregb(GUS47Counter2) = (uint8_t) data; break; /* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */ case 0x49: /* SampCtrlReg */ - GUSregb(GUS49SampCtrl) = (GUSbyte) data; + GUSregb(GUS49SampCtrl) = (uint8_t) data; break; /* case 0x4b: */ /* joystick trim not emulated */ case 0x4c: /* GUSreset */ - GUSregb(GUS4cReset) = (GUSbyte) data; + GUSregb(GUS4cReset) = (uint8_t) data; if (!(GUSregb(GUS4cReset) & 1)) /* reset... */ { GUSregd(voicewavetableirq) = 0; @@ -471,9 +471,9 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data) break; case 0x307: /* DRAMaccess */ { - GUSbyte *adr; + uint8_t *adr; adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff); - *adr = (GUSbyte) data; + *adr = (uint8_t) data; } break; } @@ -510,7 +510,7 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun char *srcaddr; char *destaddr; char msbmask = 0; - GUSbyte *gusptr; + uint8_t *gusptr; gusptr = state->gusdatapos; srcaddr = dma_addr; /* system memory address */ @@ -521,8 +521,8 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */ } - GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */ - GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */ + GUSregw(GUS42DMAStart) += (uint16_t) (count >> 4); /* ToDo: add 16bit GUS page limit? */ + GUSregb(GUS50DMAHigh) = (uint8_t) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */ if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */ { diff --git a/hw/audio/gusemu_mixer.c b/hw/audio/gusemu_mixer.c index 701e8fb..00b9861 100644 --- a/hw/audio/gusemu_mixer.c +++ b/hw/audio/gusemu_mixer.c @@ -27,26 +27,26 @@ #include "gustate.h" #define GUSregb(position) (* (gusptr+(position))) -#define GUSregw(position) (*(GUSword *) (gusptr+(position))) -#define GUSregd(position) (*(GUSdword *)(gusptr+(position))) +#define GUSregw(position) (*(uint16_t *) (gusptr+(position))) +#define GUSregd(position) (*(uint16_t *)(gusptr+(position))) -#define GUSvoice(position) (*(GUSword *)(voiceptr+(position))) +#define GUSvoice(position) (*(uint16_t *)(voiceptr+(position))) /* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples, - GUSsample *bufferpos) + int16_t *bufferpos) { /* note that byte registers are stored in the upper half of each voice register! */ - GUSbyte *gusptr; + uint8_t *gusptr; int Voice; - GUSword *voiceptr; + uint16_t *voiceptr; unsigned int count; for (count = 0; count < numsamples * 2; count++) *(bufferpos + count) = 0; /* clear */ gusptr = state->gusdatapos; - voiceptr = (GUSword *) gusptr; + voiceptr = (uint16_t *) gusptr; if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */ return; @@ -85,16 +85,16 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int if (GUSvoice(wVSRControl) & 0x400) /* 16bit */ { int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1); - GUSchar *adr; - adr = (GUSchar *) state->himemaddr + offset; + int8_t *adr; + adr = (int8_t *) state->himemaddr + offset; sample1 = (*adr & 0xff) + (*(adr + 1) * 256); sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256); } else /* 8bit */ { int offset = (CurrPos >> 9) & 0xfffff; - GUSchar *adr; - adr = (GUSchar *) state->himemaddr + offset; + int8_t *adr; + adr = (int8_t *) state->himemaddr + offset; sample1 = (*adr) * 256; sample2 = (*(adr + 1)) * 256; } @@ -171,8 +171,8 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int } /* mix samples into buffer */ - *(bufferpos + 2 * sample) += (GUSsample) ((sample1 * PanningPos) >> 4); /* right */ - *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */ + *(bufferpos + 2 * sample) += (int16_t) ((sample1 * PanningPos) >> 4); /* right */ + *(bufferpos + 2 * sample + 1) += (int16_t) ((sample1 * (15 - PanningPos)) >> 4); /* left */ } /* write back voice and volume */ GUSvoice(wVSRCurrVol) = Volume32 / 32; @@ -187,7 +187,7 @@ void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time) /* time given in microseconds */ { int requestedIRQs = 0; - GUSbyte *gusptr; + uint8_t *gusptr; gusptr = state->gusdatapos; if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */ { diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index 52d4640..5402cd1 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -520,7 +520,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) return 0; } -static int hda_audio_exit(HDACodecDevice *hda) +static void hda_audio_exit(HDACodecDevice *hda) { HDAAudioState *a = HDA_AUDIO(hda); HDAAudioStream *st; @@ -539,7 +539,6 @@ static int hda_audio_exit(HDACodecDevice *hda) } } AUD_remove_card(&a->card); - return 0; } static int hda_audio_post_load(void *opaque, int version) diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 537face..2c497eb 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -70,7 +70,7 @@ static void hda_codec_dev_realize(DeviceState *qdev, Error **errp) } } -static int hda_codec_dev_exit(DeviceState *qdev) +static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp) { HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev); HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); @@ -78,7 +78,6 @@ static int hda_codec_dev_exit(DeviceState *qdev) if (cdc->exit) { cdc->exit(dev); } - return 0; } HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) @@ -1318,7 +1317,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->realize = hda_codec_dev_realize; - k->exit = hda_codec_dev_exit; + k->unrealize = hda_codec_dev_unrealize; set_bit(DEVICE_CATEGORY_SOUND, k->categories); k->bus_type = TYPE_HDA_BUS; k->props = hda_props; diff --git a/hw/audio/intel-hda.h b/hw/audio/intel-hda.h index d784bcf..53b78da 100644 --- a/hw/audio/intel-hda.h +++ b/hw/audio/intel-hda.h @@ -38,7 +38,7 @@ typedef struct HDACodecDeviceClass DeviceClass parent_class; int (*init)(HDACodecDevice *dev); - int (*exit)(HDACodecDevice *dev); + void (*exit)(HDACodecDevice *dev); void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output); } HDACodecDeviceClass; diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 725fdc4..55fcb68 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -29,3 +29,4 @@ common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o +obj-$(CONFIG_TERMINAL3270) += terminal3270.o diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c new file mode 100644 index 0000000..b2dda01 --- /dev/null +++ b/hw/char/terminal3270.c @@ -0,0 +1,293 @@ +/* + * Terminal 3270 implementation + * + * Copyright 2017 IBM Corp. + * + * Authors: Yang Chen <bjcyang@linux.vnet.ibm.com> + * Jing Liu <liujbjl@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "sysemu/char.h" +#include "hw/s390x/3270-ccw.h" + +/* Enough spaces for different window sizes. */ +#define INPUT_BUFFER_SIZE 1000 +/* + * 1 for header, 1024*2 for datastream, 2 for tail + * Reserve enough spaces for telnet IAC escape. + */ +#define OUTPUT_BUFFER_SIZE 2051 + +typedef struct Terminal3270 { + EmulatedCcw3270Device cdev; + CharBackend chr; + uint8_t inv[INPUT_BUFFER_SIZE]; + uint8_t outv[OUTPUT_BUFFER_SIZE]; + int in_len; + int out_len; + bool handshake_done; + guint timer_tag; +} Terminal3270; + +#define TYPE_TERMINAL_3270 "x-terminal3270" +#define TERMINAL_3270(obj) \ + OBJECT_CHECK(Terminal3270, (obj), TYPE_TERMINAL_3270) + +static int terminal_can_read(void *opaque) +{ + Terminal3270 *t = opaque; + + return INPUT_BUFFER_SIZE - t->in_len; +} + +/* + * Protocol handshake done, + * signal guest by an unsolicited DE irq. + */ +static void TN3270_handshake_done(Terminal3270 *t) +{ + CcwDevice *ccw_dev = CCW_DEVICE(t); + SubchDev *sch = ccw_dev->sch; + + t->handshake_done = true; + sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END; + css_conditional_io_interrupt(sch); +} + +/* + * Called when the interval is timeout to detect + * if the client is still alive by Timing Mark. + */ +static gboolean send_timing_mark_cb(gpointer opaque) +{ + Terminal3270 *t = opaque; + const uint8_t timing[] = {0xff, 0xfd, 0x06}; + + qemu_chr_fe_write_all(&t->chr, timing, sizeof(timing)); + return true; +} + +/* + * Receive inbound data from socket. + * For data given to guest, drop the data boundary IAC, IAC_EOR. + * TODO: + * Using "Reset" key on x3270 may result multiple commands in one packet. + * This usually happens when the user meets a poor traffic of the network. + * As of now, for such case, we simply terminate the connection, + * and we should come back here later with a better solution. + */ +static void terminal_read(void *opaque, const uint8_t *buf, int size) +{ + Terminal3270 *t = opaque; + CcwDevice *ccw_dev = CCW_DEVICE(t); + SubchDev *sch = ccw_dev->sch; + int end; + + assert(size <= (INPUT_BUFFER_SIZE - t->in_len)); + + if (t->timer_tag) { + g_source_remove(t->timer_tag); + t->timer_tag = 0; + } + t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t); + + memcpy(&t->inv[t->in_len], buf, size); + t->in_len += size; + if (t->in_len < 2) { + return; + } + + if (!t->handshake_done) { + /* + * Receiving Terminal Type is the last step of handshake. + * The data format: IAC SB Terminal-Type IS <terminal type> IAC SE + * The code for Terminal-Type is 0x18, for IS is 0. + * Simply check the data format and mark handshake_done. + */ + if (t->in_len > 6 && t->inv[2] == 0x18 && t->inv[3] == 0x0 && + t->inv[t->in_len - 2] == IAC && t->inv[t->in_len - 1] == IAC_SE) { + TN3270_handshake_done(t); + t->in_len = 0; + } + return; + } + + for (end = 0; end < t->in_len - 1; end++) { + if (t->inv[end] == IAC && t->inv[end + 1] == IAC_EOR) { + break; + } + } + if (end == t->in_len - 2) { + /* Data is valid for consuming. */ + t->in_len -= 2; + sch->curr_status.scsw.dstat = SCSW_DSTAT_ATTENTION; + css_conditional_io_interrupt(sch); + } else if (end < t->in_len - 2) { + /* "Reset" key is used. */ + qemu_chr_fe_disconnect(&t->chr); + } else { + /* Gathering data. */ + return; + } +} + +static void chr_event(void *opaque, int event) +{ + Terminal3270 *t = opaque; + CcwDevice *ccw_dev = CCW_DEVICE(t); + SubchDev *sch = ccw_dev->sch; + + /* Ensure the initial status correct, always reset them. */ + t->in_len = 0; + t->out_len = 0; + t->handshake_done = false; + if (t->timer_tag) { + g_source_remove(t->timer_tag); + t->timer_tag = 0; + } + + switch (event) { + case CHR_EVENT_OPENED: + /* + * 3270 does handshake firstly by the negotiate options in + * char-socket.c. Once qemu receives the terminal-type of the + * client, mark handshake done and trigger everything rolling again. + */ + t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t); + break; + case CHR_EVENT_CLOSED: + sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END; + css_conditional_io_interrupt(sch); + break; + } +} + +static void terminal_init(EmulatedCcw3270Device *dev, Error **errp) +{ + Terminal3270 *t = TERMINAL_3270(dev); + static bool terminal_available; + + if (terminal_available) { + error_setg(errp, "Multiple 3270 terminals are not supported."); + return; + } + terminal_available = true; + qemu_chr_fe_set_handlers(&t->chr, terminal_can_read, + terminal_read, chr_event, t, NULL, true); +} + +static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda, + uint16_t count) +{ + Terminal3270 *t = TERMINAL_3270(dev); + int len; + + len = MIN(count, t->in_len); + cpu_physical_memory_write(cda, t->inv, len); + t->in_len -= len; + + return len; +} + +/* TN3270 uses binary transmission, which needs escape IAC to IAC IAC */ +static int insert_IAC_escape_char(uint8_t *outv, int out_len) +{ + int IAC_num = 0, new_out_len, i, j; + + for (i = 0; i < out_len; i++) { + if (outv[i] == IAC) { + IAC_num++; + } + } + if (IAC_num == 0) { + return out_len; + } + new_out_len = out_len + IAC_num; + for (i = out_len - 1, j = new_out_len - 1; j > i && i >= 0; i--, j--) { + outv[j] = outv[i]; + if (outv[i] == IAC) { + outv[--j] = IAC; + } + } + return new_out_len; +} + +/* + * Write 3270 outbound to socket. + * Return the count of 3270 data field if succeeded, zero if failed. + */ +static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd, + uint32_t cda, uint16_t count) +{ + Terminal3270 *t = TERMINAL_3270(dev); + int retval = 0; + + assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2); + + if (!t->handshake_done) { + if (!(t->outv[0] == IAC && t->outv[1] != IAC)) { + /* + * Before having finished 3270 negotiation, + * sending outbound data except protocol options is prohibited. + */ + return 0; + } + } + if (!qemu_chr_fe_get_driver(&t->chr)) { + /* We just say we consumed all data if there's no backend. */ + return count; + } + t->outv[0] = cmd; + cpu_physical_memory_read(cda, &t->outv[1], count); + t->out_len = count + 1; + + t->out_len = insert_IAC_escape_char(t->outv, t->out_len); + t->outv[t->out_len++] = IAC; + t->outv[t->out_len++] = IAC_EOR; + + retval = qemu_chr_fe_write_all(&t->chr, t->outv, t->out_len); + return (retval <= 0) ? 0 : (retval - 3); +} + +static Property terminal_properties[] = { + DEFINE_PROP_CHR("chardev", Terminal3270, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription terminal3270_vmstate = { + .name = TYPE_TERMINAL_3270, + .unmigratable = 1, +}; + +static void terminal_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass); + + dc->props = terminal_properties; + dc->vmsd = &terminal3270_vmstate; + ck->init = terminal_init; + ck->read_payload_3270 = read_payload_3270; + ck->write_payload_3270 = write_payload_3270; +} + +static const TypeInfo ccw_terminal_info = { + .name = TYPE_TERMINAL_3270, + .parent = TYPE_EMULATED_CCW_3270, + .instance_size = sizeof(Terminal3270), + .class_init = terminal_class_init, + .class_size = sizeof(EmulatedCcw3270Class), +}; + +static void register_types(void) +{ + type_register_static(&ccw_terminal_info); +} + +type_init(register_types) diff --git a/hw/display/cg3.c b/hw/display/cg3.c index 03d9197..7ef8a96 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -113,7 +113,7 @@ static void cg3_update_display(void *opaque) for (y = 0; y < height; y++) { int update = s->full_update; - page = y * width; + page = (ram_addr_t)y * width; update |= memory_region_get_dirty(&s->vram_mem, page, width, DIRTY_MEMORY_VGA); if (update) { diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 5a1115c..0e66dcd 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -145,7 +145,6 @@ static void update_palette_entries(TCXState *s, int start, int end) } else { s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); } - break; } tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem)); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 2073108..1d8c645 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -272,7 +272,7 @@ build_facs(GArray *table_data, BIOSLinker *linker) } /* Load chipset information in FADT */ -static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm) +static void fadt_setup(AcpiFadtDescriptorRev3 *fadt, AcpiPmInfo *pm) { fadt->model = 1; fadt->reserved1 = 0; @@ -304,6 +304,31 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm) fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL); } fadt->century = RTC_CENTURY; + + fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_RESET_REG_SUP); + fadt->reset_value = 0xf; + fadt->reset_register.space_id = AML_SYSTEM_IO; + fadt->reset_register.bit_width = 8; + fadt->reset_register.address = cpu_to_le64(ICH9_RST_CNT_IOPORT); + /* The above need not be conditional on machine type because the reset port + * happens to be the same on PIIX (pc) and ICH9 (q35). */ + QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT); + + fadt->xpm1a_event_block.space_id = AML_SYSTEM_IO; + fadt->xpm1a_event_block.bit_width = fadt->pm1_evt_len * 8; + fadt->xpm1a_event_block.address = cpu_to_le64(pm->io_base); + + fadt->xpm1a_control_block.space_id = AML_SYSTEM_IO; + fadt->xpm1a_control_block.bit_width = fadt->pm1_cnt_len * 8; + fadt->xpm1a_control_block.address = cpu_to_le64(pm->io_base + 0x4); + + fadt->xpm_timer_block.space_id = AML_SYSTEM_IO; + fadt->xpm_timer_block.bit_width = fadt->pm_tmr_len * 8; + fadt->xpm_timer_block.address = cpu_to_le64(pm->io_base + 0x8); + + fadt->xgpe0_block.space_id = AML_SYSTEM_IO; + fadt->xgpe0_block.bit_width = pm->gpe0_blk_len * 8; + fadt->xgpe0_block.address = cpu_to_le64(pm->gpe0_blk); } @@ -313,9 +338,10 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, unsigned facs_tbl_offset, unsigned dsdt_tbl_offset, const char *oem_id, const char *oem_table_id) { - AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); + AcpiFadtDescriptorRev3 *fadt = acpi_data_push(table_data, sizeof(*fadt)); unsigned fw_ctrl_offset = (char *)&fadt->firmware_ctrl - table_data->data; unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data; + unsigned xdsdt_entry_offset = (char *)&fadt->Xdsdt - table_data->data; /* FACS address to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, @@ -327,9 +353,12 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt), ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); + bios_linker_loader_add_pointer(linker, + ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->Xdsdt), + ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id); + (void *)fadt, "FACP", sizeof(*fadt), 3, oem_id, oem_table_id); } void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, diff --git a/hw/input/hid.c b/hw/input/hid.c index fa9cc4c..93887ec 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -256,6 +256,10 @@ static void hid_keyboard_process_keycode(HIDState *hs) slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; keycode = hs->kbd.keycodes[slot]; + if (!hs->n) { + trace_hid_kbd_queue_empty(); + } + key = keycode & 0x7f; index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1); hid_code = hid_usage_keys[index]; diff --git a/hw/input/trace-events b/hw/input/trace-events index f3bfbed..5a87818 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -24,6 +24,7 @@ milkymist_softusb_pulse_irq(void) "Pulse IRQ" # hw/input/hid.c hid_kbd_queue_full(void) "queue full" +hid_kbd_queue_empty(void) "queue empty" # hw/input/virtio virtio_input_queue_full(void) "queue full" diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index a98c799..febc469 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -61,6 +61,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu) } next = now + (uint64_t)wait * TIMER_PERIOD; timer_mod(cpu->env.timer, next); + qemu_cpu_kick(CPU(cpu)); } void cpu_openrisc_count_start(OpenRISCCPU *cpu) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index f9218aa..bf4221d 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -58,12 +58,6 @@ typedef struct I440FXState { #define XEN_PIIX_NUM_PIRQS 128ULL #define PIIX_PIRQC 0x60 -/* - * Reset Control Register: PCI-accessible ISA-Compatible Register at address - * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000). - */ -#define RCR_IOPORT 0xcf9 - typedef struct PIIX3State { PCIDevice dev; diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c new file mode 100644 index 0000000..a7a5b41 --- /dev/null +++ b/hw/s390x/3270-ccw.c @@ -0,0 +1,174 @@ +/* + * Emulated ccw-attached 3270 implementation + * + * Copyright 2017 IBM Corp. + * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com> + * Jing Liu <liujbjl@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "cpu.h" +#include "hw/s390x/css.h" +#include "hw/s390x/css-bridge.h" +#include "hw/s390x/3270-ccw.h" + +/* Handle READ ccw commands from guest */ +static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw) +{ + EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev); + CcwDevice *ccw_dev = CCW_DEVICE(dev); + int len; + + if (!ccw->cda) { + return -EFAULT; + } + + len = ck->read_payload_3270(dev, ccw->cda, ccw->count); + ccw_dev->sch->curr_status.scsw.count = ccw->count - len; + + return 0; +} + +/* Handle WRITE ccw commands to write data to client */ +static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw) +{ + EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev); + CcwDevice *ccw_dev = CCW_DEVICE(dev); + int len; + + if (!ccw->cda) { + return -EFAULT; + } + + len = ck->write_payload_3270(dev, ccw->cmd_code, ccw->cda, ccw->count); + + if (len <= 0) { + return -EIO; + } + + ccw_dev->sch->curr_status.scsw.count = ccw->count - len; + return 0; +} + +static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw) +{ + int rc = 0; + EmulatedCcw3270Device *dev = sch->driver_data; + + switch (ccw.cmd_code) { + case TC_WRITESF: + case TC_WRITE: + case TC_EWRITE: + case TC_EWRITEA: + rc = handle_payload_3270_write(dev, &ccw); + break; + case TC_RDBUF: + case TC_READMOD: + rc = handle_payload_3270_read(dev, &ccw); + break; + default: + rc = -ENOSYS; + break; + } + + if (rc == -EIO) { + /* I/O error, specific devices generate specific conditions */ + SCSW *s = &sch->curr_status.scsw; + + sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK; + sch->sense_data[0] = 0x40; /* intervention-req */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + } + + return rc; +} + +static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp) +{ + uint16_t chpid; + EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds); + EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev); + CcwDevice *cdev = CCW_DEVICE(ds); + CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev); + SubchDev *sch = css_create_virtual_sch(cdev->devno, errp); + Error *err = NULL; + + if (!sch) { + return; + } + + if (!ck->init) { + goto out_err; + } + + sch->driver_data = dev; + cdev->sch = sch; + chpid = css_find_free_chpid(sch->cssid); + + if (chpid > MAX_CHPID) { + error_setg(&err, "No available chpid to use."); + goto out_err; + } + + sch->id.reserved = 0xff; + sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE; + css_sch_build_virtual_schib(sch, (uint8_t)chpid, + EMULATED_CCW_3270_CHPID_TYPE); + sch->ccw_cb = emulated_ccw_3270_cb; + + ck->init(dev, &err); + if (err) { + goto out_err; + } + + cdk->realize(cdev, &err); + if (err) { + goto out_err; + } + + return; + +out_err: + error_propagate(errp, err); + css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); + cdev->sch = NULL; + g_free(sch); +} + +static Property emulated_ccw_3270_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = emulated_ccw_3270_properties; + dc->bus_type = TYPE_VIRTUAL_CSS_BUS; + dc->realize = emulated_ccw_3270_realize; + dc->hotpluggable = false; +} + +static const TypeInfo emulated_ccw_3270_info = { + .name = TYPE_EMULATED_CCW_3270, + .parent = TYPE_CCW_DEVICE, + .instance_size = sizeof(EmulatedCcw3270Device), + .class_init = emulated_ccw_3270_class_init, + .class_size = sizeof(EmulatedCcw3270Class), + .abstract = true, +}; + +static void emulated_ccw_register(void) +{ + type_register_static(&emulated_ccw_3270_info); +} + +type_init(emulated_ccw_register) diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 41ac4ec..36bd4b1 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -7,6 +7,7 @@ obj-y += sclpcpu.o obj-y += ipl.o obj-y += css.o obj-y += s390-virtio-ccw.o +obj-y += 3270-ccw.o obj-y += virtio-ccw.o obj-y += css-bridge.o obj-y += ccw-device.o diff --git a/hw/s390x/css.c b/hw/s390x/css.c index c03bb20..15c4f4b 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -576,6 +576,9 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END; s->cpa = sch->channel_prog + 8; break; + case -EIO: + /* I/O errors, status depends on specific devices */ + break; case -ENOSYS: /* unsupported command, generate unit check (command reject) */ s->ctrl &= ~SCSW_ACTL_START_PEND; @@ -1302,6 +1305,27 @@ bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid) (MAX_SCHID + 1) / sizeof(unsigned long)); } +unsigned int css_find_free_chpid(uint8_t cssid) +{ + CssImage *css = channel_subsys.css[cssid]; + unsigned int chpid; + + if (!css) { + return MAX_CHPID + 1; + } + + for (chpid = 0; chpid <= MAX_CHPID; chpid++) { + /* skip reserved chpid */ + if (chpid == VIRTIO_CCW_CHPID) { + continue; + } + if (!css->chpids[chpid].in_use) { + return chpid; + } + } + return MAX_CHPID + 1; +} + static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) { CssImage *css; diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 7978c7d..75d3c68 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -17,8 +17,10 @@ #include "cpu.h" #include "elf.h" #include "hw/loader.h" +#include "hw/boards.h" #include "hw/s390x/virtio-ccw.h" #include "hw/s390x/css.h" +#include "hw/s390x/ebcdic.h" #include "ipl.h" #include "qemu/error-report.h" @@ -243,12 +245,17 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl) ipl->iplb.pbt = S390_IPL_TYPE_CCW; ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno); ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3; - return true; } else if (sd) { SCSIBus *bus = scsi_bus_from_device(sd); VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus); VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev); - CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw); + CcwDevice *ccw_dev; + + ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw), + TYPE_CCW_DEVICE); + if (!ccw_dev) { /* It might be a PCI device instead */ + return false; + } ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN); ipl->iplb.blk0_len = @@ -259,13 +266,39 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl) ipl->iplb.scsi.channel = cpu_to_be16(sd->channel); ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno); ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3; - return true; + } else { + return false; /* unknown device */ } + + if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) { + ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID; + } + return true; } return false; } +int s390_ipl_set_loadparm(uint8_t *loadparm) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL); + + if (lp) { + int i; + + /* lp is an uppercase string without leading/embedded spaces */ + for (i = 0; i < 8 && lp[i]; i++) { + loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]]; + } + + g_free(lp); + return 0; + } + + return -1; +} + static int load_netboot_image(Error **errp) { S390IPLState *ipl = get_ipl_device(); diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 46930e4..8a705e0 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -57,6 +57,8 @@ struct IplBlockQemuScsi { } QEMU_PACKED; typedef struct IplBlockQemuScsi IplBlockQemuScsi; +#define DIAG308_FLAGS_LP_VALID 0x80 + union IplParameterBlock { struct { uint32_t len; @@ -82,6 +84,7 @@ union IplParameterBlock { } QEMU_PACKED; typedef union IplParameterBlock IplParameterBlock; +int s390_ipl_set_loadparm(uint8_t *loadparm); void s390_ipl_update_diag308(IplParameterBlock *iplb); void s390_ipl_prepare_cpu(S390CPU *cpu); IplParameterBlock *s390_ipl_get_iplb(void); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 04bd0eb..fdd4384 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -274,6 +274,36 @@ bool cpu_model_allowed(void) return true; } +static char *machine_get_loadparm(Object *obj, Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + return g_memdup(ms->loadparm, sizeof(ms->loadparm)); +} + +static void machine_set_loadparm(Object *obj, const char *val, Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + int i; + + for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) { + uint8_t c = toupper(val[i]); /* mimic HMC */ + + if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') || + (c == ' ')) { + ms->loadparm[i] = c; + } else { + error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)", + c, c); + return; + } + } + + for (; i < sizeof(ms->loadparm); i++) { + ms->loadparm[i] = ' '; /* pad right with spaces */ + } +} + static inline void s390_machine_initfn(Object *obj) { object_property_add_bool(obj, "aes-key-wrap", @@ -291,6 +321,13 @@ static inline void s390_machine_initfn(Object *obj) "enable/disable DEA key wrapping using the CPACF wrapping key", NULL); object_property_set_bool(obj, true, "dea-key-wrap", NULL); + object_property_add_str(obj, "loadparm", + machine_get_loadparm, machine_set_loadparm, NULL); + object_property_set_description(obj, "loadparm", + "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted" + " to upper case) to pass to machine loader, boot manager," + " and guest kernel", + NULL); } static const TypeInfo ccw_machine_info = { diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index e741da1..b4f6dd5 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -23,6 +23,7 @@ #include "hw/s390x/sclp.h" #include "hw/s390x/event-facility.h" #include "hw/s390x/s390-pci-bus.h" +#include "hw/s390x/ipl.h" static inline SCLPDevice *get_sclp_device(void) { @@ -57,6 +58,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) int cpu_count = 0; int rnsize, rnmax; int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state)); + IplParameterBlock *ipib = s390_ipl_get_iplb(); CPU_FOREACH(cpu) { cpu_count++; @@ -129,6 +131,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) read_info->rnmax2 = cpu_to_be64(rnmax); } + if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) { + memcpy(&read_info->loadparm, &ipib->loadparm, + sizeof(read_info->loadparm)); + } else { + s390_ipl_set_loadparm(read_info->loadparm); + } + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs index 5a2248b..54d8754 100644 --- a/hw/scsi/Makefile.objs +++ b/hw/scsi/Makefile.objs @@ -10,5 +10,5 @@ obj-$(CONFIG_PSERIES) += spapr_vscsi.o ifeq ($(CONFIG_VIRTIO),y) obj-y += virtio-scsi.o virtio-scsi-dataplane.o -obj-$(CONFIG_VHOST_SCSI) += vhost-scsi.o +obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-common.o vhost-scsi.o endif diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 84b8caf..804122a 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2138,15 +2138,15 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, case MFI_SEQ: trace_megasas_mmio_writel("MFI_SEQ", val); /* Magic sequence to start ADP reset */ - if (adp_reset_seq[s->adp_reset] == val) { - s->adp_reset++; + if (adp_reset_seq[s->adp_reset++] == val) { + if (s->adp_reset == 6) { + s->adp_reset = 0; + s->diag = MFI_DIAG_WRITE_ENABLE; + } } else { s->adp_reset = 0; s->diag = 0; } - if (s->adp_reset == 6) { - s->diag = MFI_DIAG_WRITE_ENABLE; - } break; case MFI_DIAG: trace_megasas_mmio_writel("MFI_DIAG", val); diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c new file mode 100644 index 0000000..e41c031 --- /dev/null +++ b/hw/scsi/vhost-scsi-common.c @@ -0,0 +1,143 @@ +/* + * vhost-scsi-common + * + * Copyright (c) 2016 Nutanix Inc. All rights reserved. + * + * Author: + * Felipe Franciosi <felipe@nutanix.com> + * + * This work is largely based on the "vhost-scsi" implementation by: + * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> + * Nicholas Bellinger <nab@risingtidesystems.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include <linux/vhost.h> +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "migration/migration.h" +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-scsi-common.h" +#include "hw/virtio/virtio-scsi.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" +#include "hw/fw-path-provider.h" + +int vhost_scsi_common_start(VHostSCSICommon *vsc) +{ + int ret, i; + VirtIODevice *vdev = VIRTIO_DEVICE(vsc); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return -ENOSYS; + } + + ret = vhost_dev_enable_notifiers(&vsc->dev, vdev); + if (ret < 0) { + return ret; + } + + ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier"); + goto err_host_notifiers; + } + + vsc->dev.acked_features = vdev->guest_features; + ret = vhost_dev_start(&vsc->dev, vdev); + if (ret < 0) { + error_report("Error start vhost dev"); + goto err_guest_notifiers; + } + + /* guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < vsc->dev.nvqs; i++) { + vhost_virtqueue_mask(&vsc->dev, vdev, vsc->dev.vq_index + i, false); + } + + return ret; + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(&vsc->dev, vdev); + return ret; +} + +void vhost_scsi_common_stop(VHostSCSICommon *vsc) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vsc); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret = 0; + + vhost_dev_stop(&vsc->dev, vdev); + + if (k->set_guest_notifiers) { + ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + } + } + assert(ret >= 0); + + vhost_dev_disable_notifiers(&vsc->dev, vdev); +} + +uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev); + + return vhost_get_features(&vsc->dev, vsc->feature_bits, features); +} + +void vhost_scsi_common_set_config(VirtIODevice *vdev, const uint8_t *config) +{ + VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + + if ((uint32_t)virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size || + (uint32_t)virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) { + error_report("vhost-scsi does not support changing the sense data and " + "CDB sizes"); + exit(1); + } +} + +/* + * Implementation of an interface to adjust firmware path + * for the bootindex property handling. + */ +char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus, + DeviceState *dev) +{ + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); + /* format: /channel@channel/vhost-scsi@target,lun */ + return g_strdup_printf("/channel@%x/%s@%x,%x", vsc->channel, + qdev_fw_name(dev), vsc->target, vsc->lun); +} + +static const TypeInfo vhost_scsi_common_info = { + .name = TYPE_VHOST_SCSI_COMMON, + .parent = TYPE_VIRTIO_SCSI_COMMON, + .instance_size = sizeof(VHostSCSICommon), + .abstract = true, +}; + +static void virtio_register_types(void) +{ + type_register_static(&vhost_scsi_common_info); +} + +type_init(virtio_register_types) diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index f53bc17..8f53ac3 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -42,13 +42,14 @@ static const int kernel_feature_bits[] = { static int vhost_scsi_set_endpoint(VHostSCSI *s) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); - const VhostOps *vhost_ops = s->dev.vhost_ops; + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + const VhostOps *vhost_ops = vsc->dev.vhost_ops; struct vhost_scsi_target backend; int ret; memset(&backend, 0, sizeof(backend)); pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn); - ret = vhost_ops->vhost_scsi_set_endpoint(&s->dev, &backend); + ret = vhost_ops->vhost_scsi_set_endpoint(&vsc->dev, &backend); if (ret < 0) { return -errno; } @@ -58,130 +59,62 @@ static int vhost_scsi_set_endpoint(VHostSCSI *s) static void vhost_scsi_clear_endpoint(VHostSCSI *s) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); struct vhost_scsi_target backend; - const VhostOps *vhost_ops = s->dev.vhost_ops; + const VhostOps *vhost_ops = vsc->dev.vhost_ops; memset(&backend, 0, sizeof(backend)); pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn); - vhost_ops->vhost_scsi_clear_endpoint(&s->dev, &backend); + vhost_ops->vhost_scsi_clear_endpoint(&vsc->dev, &backend); } static int vhost_scsi_start(VHostSCSI *s) { - int ret, abi_version, i; - VirtIODevice *vdev = VIRTIO_DEVICE(s); - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); - const VhostOps *vhost_ops = s->dev.vhost_ops; - - if (!k->set_guest_notifiers) { - error_report("binding does not support guest notifiers"); - return -ENOSYS; - } + int ret, abi_version; + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + const VhostOps *vhost_ops = vsc->dev.vhost_ops; - ret = vhost_ops->vhost_scsi_get_abi_version(&s->dev, &abi_version); + ret = vhost_ops->vhost_scsi_get_abi_version(&vsc->dev, &abi_version); if (ret < 0) { return -errno; } if (abi_version > VHOST_SCSI_ABI_VERSION) { error_report("vhost-scsi: The running tcm_vhost kernel abi_version:" - " %d is greater than vhost_scsi userspace supports: %d, please" - " upgrade your version of QEMU", abi_version, + " %d is greater than vhost_scsi userspace supports: %d," + " please upgrade your version of QEMU", abi_version, VHOST_SCSI_ABI_VERSION); return -ENOSYS; } - ret = vhost_dev_enable_notifiers(&s->dev, vdev); + ret = vhost_scsi_common_start(vsc); if (ret < 0) { return ret; } - s->dev.acked_features = vdev->guest_features; - ret = vhost_dev_start(&s->dev, vdev); - if (ret < 0) { - error_report("Error start vhost dev"); - goto err_notifiers; - } - ret = vhost_scsi_set_endpoint(s); if (ret < 0) { - error_report("Error set vhost-scsi endpoint"); - goto err_vhost_stop; - } - - ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true); - if (ret < 0) { - error_report("Error binding guest notifier"); - goto err_endpoint; - } - - /* guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < s->dev.nvqs; i++) { - vhost_virtqueue_mask(&s->dev, vdev, s->dev.vq_index + i, false); + error_report("Error setting vhost-scsi endpoint"); + vhost_scsi_common_stop(vsc); } return ret; - -err_endpoint: - vhost_scsi_clear_endpoint(s); -err_vhost_stop: - vhost_dev_stop(&s->dev, vdev); -err_notifiers: - vhost_dev_disable_notifiers(&s->dev, vdev); - return ret; } static void vhost_scsi_stop(VHostSCSI *s) { - VirtIODevice *vdev = VIRTIO_DEVICE(s); - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); - int ret = 0; - - if (k->set_guest_notifiers) { - ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); - if (ret < 0) { - error_report("vhost guest notifier cleanup failed: %d", ret); - } - } - assert(ret >= 0); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); vhost_scsi_clear_endpoint(s); - vhost_dev_stop(&s->dev, vdev); - vhost_dev_disable_notifiers(&s->dev, vdev); -} - -static uint64_t vhost_scsi_get_features(VirtIODevice *vdev, - uint64_t features, - Error **errp) -{ - VHostSCSI *s = VHOST_SCSI(vdev); - - return vhost_get_features(&s->dev, kernel_feature_bits, features); -} - -static void vhost_scsi_set_config(VirtIODevice *vdev, - const uint8_t *config) -{ - VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - - if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size || - (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) { - error_report("vhost-scsi does not support changing the sense data and CDB sizes"); - exit(1); - } + vhost_scsi_common_stop(vsc); } static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) { - VHostSCSI *s = (VHostSCSI *)vdev; + VHostSCSI *s = VHOST_SCSI(vdev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK); - if (s->dev.started == start) { + if (vsc->dev.started == start) { return; } @@ -190,10 +123,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) ret = vhost_scsi_start(s); if (ret < 0) { - error_report("virtio-scsi: unable to start vhost: %s", - strerror(-ret)); - - /* There is no userspace virtio-scsi fallback so exit */ + error_report("unable to start vhost-scsi: %s", strerror(-ret)); exit(1); } } else { @@ -208,7 +138,7 @@ static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) static void vhost_scsi_realize(DeviceState *dev, Error **errp) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); - VHostSCSI *s = VHOST_SCSI(dev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); Error *err = NULL; int vhostfd = -1; int ret; @@ -243,21 +173,21 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) goto close_fd; } - error_setg(&s->migration_blocker, + error_setg(&vsc->migration_blocker, "vhost-scsi does not support migration"); - migrate_add_blocker(s->migration_blocker, &err); + migrate_add_blocker(vsc->migration_blocker, &err); if (err) { error_propagate(errp, err); - error_free(s->migration_blocker); + error_free(vsc->migration_blocker); goto close_fd; } - s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; - s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs); - s->dev.vq_index = 0; - s->dev.backend_features = 0; + vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; + vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); + vsc->dev.vq_index = 0; + vsc->dev.backend_features = 0; - ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd, + ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd, VHOST_BACKEND_TYPE_KERNEL, 0); if (ret < 0) { error_setg(errp, "vhost-scsi: vhost initialization failed: %s", @@ -266,16 +196,16 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) } /* At present, channel and lun both are 0 for bootable vhost-scsi disk */ - s->channel = 0; - s->lun = 0; + vsc->channel = 0; + vsc->lun = 0; /* Note: we can also get the minimum tpgt from kernel */ - s->target = vs->conf.boot_tpgt; + vsc->target = vs->conf.boot_tpgt; return; free_vqs: - migrate_del_blocker(s->migration_blocker); - g_free(s->dev.vqs); + migrate_del_blocker(vsc->migration_blocker); + g_free(vsc->dev.vqs); close_fd: close(vhostfd); return; @@ -284,42 +214,28 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VHostSCSI *s = VHOST_SCSI(dev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); - migrate_del_blocker(s->migration_blocker); - error_free(s->migration_blocker); + migrate_del_blocker(vsc->migration_blocker); + error_free(vsc->migration_blocker); /* This will stop vhost backend. */ vhost_scsi_set_status(vdev, 0); - vhost_dev_cleanup(&s->dev); - g_free(s->dev.vqs); + vhost_dev_cleanup(&vsc->dev); + g_free(vsc->dev.vqs); virtio_scsi_common_unrealize(dev, errp); } -/* - * Implementation of an interface to adjust firmware path - * for the bootindex property handling. - */ -static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus, - DeviceState *dev) -{ - VHostSCSI *s = VHOST_SCSI(dev); - /* format: channel@channel/vhost-scsi@target,lun */ - return g_strdup_printf("/channel@%x/%s@%x,%x", s->channel, - qdev_fw_name(dev), s->target, s->lun); -} - static Property vhost_scsi_properties[] = { - DEFINE_PROP_STRING("vhostfd", VHostSCSI, parent_obj.conf.vhostfd), - DEFINE_PROP_STRING("wwpn", VHostSCSI, parent_obj.conf.wwpn), - DEFINE_PROP_UINT32("boot_tpgt", VHostSCSI, parent_obj.conf.boot_tpgt, 0), - DEFINE_PROP_UINT32("num_queues", VHostSCSI, parent_obj.conf.num_queues, 1), - DEFINE_PROP_UINT32("max_sectors", VHostSCSI, parent_obj.conf.max_sectors, - 0xFFFF), - DEFINE_PROP_UINT32("cmd_per_lun", VHostSCSI, parent_obj.conf.cmd_per_lun, - 128), + DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd), + DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn), + DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0), + DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1), + DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors, + 0xFFFF), + DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128), DEFINE_PROP_END_OF_LIST(), }; @@ -333,23 +249,25 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->realize = vhost_scsi_realize; vdc->unrealize = vhost_scsi_unrealize; - vdc->get_features = vhost_scsi_get_features; - vdc->set_config = vhost_scsi_set_config; + vdc->get_features = vhost_scsi_common_get_features; + vdc->set_config = vhost_scsi_common_set_config; vdc->set_status = vhost_scsi_set_status; - fwc->get_dev_path = vhost_scsi_get_fw_dev_path; + fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; } static void vhost_scsi_instance_init(Object *obj) { - VHostSCSI *dev = VHOST_SCSI(obj); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj); + + vsc->feature_bits = kernel_feature_bits; - device_add_bootindex_property(obj, &dev->bootindex, "bootindex", NULL, - DEVICE(dev), NULL); + device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL, + DEVICE(vsc), NULL); } static const TypeInfo vhost_scsi_info = { .name = TYPE_VHOST_SCSI, - .parent = TYPE_VIRTIO_SCSI_COMMON, + .parent = TYPE_VHOST_SCSI_COMMON, .instance_size = sizeof(VHostSCSI), .class_init = vhost_scsi_class_init, .instance_init = vhost_scsi_instance_init, diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 7557546..4a106da 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -202,7 +202,7 @@ pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri) uint32_t len_log2; uint32_t ring_size; - if (ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) { + if (!ri->numPages || ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) { return -1; } ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE; diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index daab0d5..a41b0d6 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -267,7 +267,7 @@ static void ccid_card_vscard_drop_connection(PassthruState *card) Chardev *chr = qemu_chr_fe_get_driver(&card->cs); qemu_chr_fe_deinit(&card->cs); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); card->vscard_in_pos = card->vscard_in_hdr = 0; } diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 0efe62f..b001a27 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1433,7 +1433,7 @@ static void usbredir_unrealize(USBDevice *udev, Error **errp) Chardev *chr = qemu_chr_fe_get_driver(&dev->cs); qemu_chr_fe_deinit(&dev->cs); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); /* Note must be done after qemu_chr_close, as that causes a close event */ qemu_bh_delete(dev->chardev_close_bh); diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 6b33b9f..a8f12ee 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -119,6 +119,9 @@ void vfio_region_write(void *opaque, hwaddr addr, case 4: buf.dword = cpu_to_le32(data); break; + case 8: + buf.qword = cpu_to_le64(data); + break; default: hw_error("vfio: unsupported write size, %d bytes", size); break; @@ -173,6 +176,9 @@ uint64_t vfio_region_read(void *opaque, case 4: data = le32_to_cpu(buf.dword); break; + case 8: + data = le64_to_cpu(buf.qword); + break; default: hw_error("vfio: unsupported read size, %d bytes", size); break; @@ -190,6 +196,14 @@ const MemoryRegionOps vfio_region_ops = { .read = vfio_region_read, .write = vfio_region_write, .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, }; /* diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 03a3d01..32aca77 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2625,8 +2625,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (!(~vdev->host.domain || ~vdev->host.bus || ~vdev->host.slot || ~vdev->host.function)) { error_setg(errp, "No provided host device"); - error_append_hint(errp, "Use -vfio-pci,host=DDDD:BB:DD.F " - "or -vfio-pci,sysfsdev=PATH_TO_DEVICE\n"); + error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F " + "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n"); return; } vdev->vbasedev.sysfsdev = diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c index ae76150..a9055e9 100644 --- a/hw/xen/xen-common.c +++ b/hw/xen/xen-common.c @@ -38,7 +38,7 @@ static int store_dev_info(int domid, Chardev *cs, const char *string) int ret = -1; /* Only continue if we're talking to a pty. */ - if (strncmp(cs->filename, "pty:", 4)) { + if (!CHARDEV_IS_PTY(cs)) { return 0; } pts = cs->filename + 4; diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index dbe2f08..140efa8 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -39,6 +39,14 @@ struct RAMBlock { QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers; int fd; size_t page_size; + /* dirty bitmap used during migration */ + unsigned long *bmap; + /* bitmap of pages that haven't been sent even once + * only maintained and used in postcopy at the moment + * where it's used to send the dirtymap at the start + * of the postcopy phase + */ + unsigned long *unsentmap; }; static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset) @@ -360,16 +368,15 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, static inline -uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest, - RAMBlock *rb, +uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, ram_addr_t start, ram_addr_t length, uint64_t *real_dirty_pages) { ram_addr_t addr; - start = rb->offset + start; unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); uint64_t num_dirty = 0; + unsigned long *dest = rb->bmap; /* start address is aligned at the start of a word? */ if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) { diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 4cc3630..293ee45 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -131,17 +131,37 @@ typedef struct AcpiTableHeader AcpiTableHeader; uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ \ uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \ uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \ - uint8_t century; /* Index to century in RTC CMOS RAM */ - -struct AcpiFadtDescriptorRev1 -{ - ACPI_FADT_COMMON_DEF - uint8_t reserved4; /* Reserved */ - uint8_t reserved4a; /* Reserved */ - uint8_t reserved4b; /* Reserved */ - uint32_t flags; -} QEMU_PACKED; -typedef struct AcpiFadtDescriptorRev1 AcpiFadtDescriptorRev1; + uint8_t century; /* Index to century in RTC CMOS RAM */ \ + /* IA-PC Boot Architecture Flags (see below for individual flags) */ \ + uint16_t boot_flags; \ + uint8_t reserved; /* Reserved, must be zero */ \ + /* Miscellaneous flag bits (see below for individual flags) */ \ + uint32_t flags; \ + /* 64-bit address of the Reset register */ \ + struct AcpiGenericAddress reset_register; \ + /* Value to write to the reset_register port to reset the system */ \ + uint8_t reset_value; \ + /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */ \ + uint16_t arm_boot_flags; \ + uint8_t minor_revision; /* FADT Minor Revision (ACPI 5.1) */ \ + uint64_t Xfacs; /* 64-bit physical address of FACS */ \ + uint64_t Xdsdt; /* 64-bit physical address of DSDT */ \ + /* 64-bit Extended Power Mgt 1a Event Reg Blk address */ \ + struct AcpiGenericAddress xpm1a_event_block; \ + /* 64-bit Extended Power Mgt 1b Event Reg Blk address */ \ + struct AcpiGenericAddress xpm1b_event_block; \ + /* 64-bit Extended Power Mgt 1a Control Reg Blk address */ \ + struct AcpiGenericAddress xpm1a_control_block; \ + /* 64-bit Extended Power Mgt 1b Control Reg Blk address */ \ + struct AcpiGenericAddress xpm1b_control_block; \ + /* 64-bit Extended Power Mgt 2 Control Reg Blk address */ \ + struct AcpiGenericAddress xpm2_control_block; \ + /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ \ + struct AcpiGenericAddress xpm_timer_block; \ + /* 64-bit Extended General Purpose Event 0 Reg Blk address */ \ + struct AcpiGenericAddress xgpe0_block; \ + /* 64-bit Extended General Purpose Event 1 Reg Blk address */ \ + struct AcpiGenericAddress xgpe1_block; \ struct AcpiGenericAddress { uint8_t space_id; /* Address space where struct or register exists */ @@ -151,38 +171,13 @@ struct AcpiGenericAddress { uint64_t address; /* 64-bit address of struct or register */ } QEMU_PACKED; +struct AcpiFadtDescriptorRev3 { + ACPI_FADT_COMMON_DEF +} QEMU_PACKED; +typedef struct AcpiFadtDescriptorRev3 AcpiFadtDescriptorRev3; + struct AcpiFadtDescriptorRev5_1 { ACPI_FADT_COMMON_DEF - /* IA-PC Boot Architecture Flags (see below for individual flags) */ - uint16_t boot_flags; - uint8_t reserved; /* Reserved, must be zero */ - /* Miscellaneous flag bits (see below for individual flags) */ - uint32_t flags; - /* 64-bit address of the Reset register */ - struct AcpiGenericAddress reset_register; - /* Value to write to the reset_register port to reset the system */ - uint8_t reset_value; - /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */ - uint16_t arm_boot_flags; - uint8_t minor_revision; /* FADT Minor Revision (ACPI 5.1) */ - uint64_t Xfacs; /* 64-bit physical address of FACS */ - uint64_t Xdsdt; /* 64-bit physical address of DSDT */ - /* 64-bit Extended Power Mgt 1a Event Reg Blk address */ - struct AcpiGenericAddress xpm1a_event_block; - /* 64-bit Extended Power Mgt 1b Event Reg Blk address */ - struct AcpiGenericAddress xpm1b_event_block; - /* 64-bit Extended Power Mgt 1a Control Reg Blk address */ - struct AcpiGenericAddress xpm1a_control_block; - /* 64-bit Extended Power Mgt 1b Control Reg Blk address */ - struct AcpiGenericAddress xpm1b_control_block; - /* 64-bit Extended Power Mgt 2 Control Reg Blk address */ - struct AcpiGenericAddress xpm2_control_block; - /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ - struct AcpiGenericAddress xpm_timer_block; - /* 64-bit Extended General Purpose Event 0 Reg Blk address */ - struct AcpiGenericAddress xgpe0_block; - /* 64-bit Extended General Purpose Event 1 Reg Blk address */ - struct AcpiGenericAddress xgpe1_block; /* 64-bit Sleep Control register (ACPI 5.0) */ struct AcpiGenericAddress sleep_control; /* 64-bit Sleep Status register (ACPI 5.0) */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index f278b3a..416aaa5 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -303,6 +303,12 @@ typedef struct PCII440FXState PCII440FXState; #define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX" +/* + * Reset Control Register: PCI-accessible ISA-Compatible Register at address + * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000). + */ +#define RCR_IOPORT 0xcf9 + PCIBus *i440fx_init(const char *host_type, const char *pci_type, PCII440FXState **pi440fx_state, int *piix_devfn, ISABus **isa_bus, qemu_irq *pic, diff --git a/include/hw/s390x/3270-ccw.h b/include/hw/s390x/3270-ccw.h new file mode 100644 index 0000000..46bee25 --- /dev/null +++ b/include/hw/s390x/3270-ccw.h @@ -0,0 +1,53 @@ +/* + * Emulated ccw-attached 3270 definitions + * + * Copyright 2017 IBM Corp. + * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com> + * Jing Liu <liujbjl@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef HW_S390X_3270_CCW_H +#define HW_S390X_3270_CCW_H + +#include "hw/sysbus.h" +#include "hw/s390x/css.h" +#include "hw/s390x/ccw-device.h" + +#define EMULATED_CCW_3270_CU_TYPE 0x3270 +#define EMULATED_CCW_3270_CHPID_TYPE 0x1a + +#define TYPE_EMULATED_CCW_3270 "emulated-ccw-3270" + +/* Local Channel Commands */ +#define TC_WRITE 0x01 /* Write */ +#define TC_RDBUF 0x02 /* Read buffer */ +#define TC_EWRITE 0x05 /* Erase write */ +#define TC_READMOD 0x06 /* Read modified */ +#define TC_EWRITEA 0x0d /* Erase write alternate */ +#define TC_WRITESF 0x11 /* Write structured field */ + +#define EMULATED_CCW_3270(obj) \ + OBJECT_CHECK(EmulatedCcw3270Device, (obj), TYPE_EMULATED_CCW_3270) +#define EMULATED_CCW_3270_CLASS(klass) \ + OBJECT_CLASS_CHECK(EmulatedCcw3270Class, (klass), TYPE_EMULATED_CCW_3270) +#define EMULATED_CCW_3270_GET_CLASS(obj) \ + OBJECT_GET_CLASS(EmulatedCcw3270Class, (obj), TYPE_EMULATED_CCW_3270) + +typedef struct EmulatedCcw3270Device { + CcwDevice parent_obj; +} EmulatedCcw3270Device; + +typedef struct EmulatedCcw3270Class { + CCWDeviceClass parent_class; + + void (*init)(EmulatedCcw3270Device *, Error **); + int (*read_payload_3270)(EmulatedCcw3270Device *, uint32_t, uint16_t); + int (*write_payload_3270)(EmulatedCcw3270Device *, uint8_t, uint32_t, + uint16_t); +} EmulatedCcw3270Class; + +#endif diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index f1f0d7f..e61fa74 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -28,6 +28,7 @@ #define MAX_CIWS 62 #define VIRTUAL_CSSID 0xfe +#define VIRTIO_CCW_CHPID 0 /* used by convention */ typedef struct CIW { uint8_t type; @@ -115,6 +116,7 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno, SubchDev *sch); void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type); +unsigned int css_find_free_chpid(uint8_t cssid); uint16_t css_build_subchannel_id(SubchDev *sch); void css_reset(void); void css_reset_sch(SubchDev *sch); diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 6ecae00..7b8a3e4 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -28,6 +28,7 @@ typedef struct S390CcwMachineState { /*< public >*/ bool aes_key_wrap; bool dea_key_wrap; + uint8_t loadparm[8]; } S390CcwMachineState; typedef struct S390CcwMachineClass { diff --git a/include/hw/virtio/vhost-scsi-common.h b/include/hw/virtio/vhost-scsi-common.h new file mode 100644 index 0000000..4553be4 --- /dev/null +++ b/include/hw/virtio/vhost-scsi-common.h @@ -0,0 +1,48 @@ +/* + * vhost_scsi host device + * + * Copyright (c) 2016 Nutanix Inc. All rights reserved. + * + * Author: + * Felipe Franciosi <felipe@nutanix.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef VHOST_SCSI_COMMON_H +#define VHOST_SCSI_COMMON_H + +#include "qemu-common.h" +#include "hw/qdev.h" +#include "hw/virtio/virtio-scsi.h" +#include "hw/virtio/vhost.h" +#include "hw/fw-path-provider.h" + +#define TYPE_VHOST_SCSI_COMMON "vhost-scsi-common" +#define VHOST_SCSI_COMMON(obj) \ + OBJECT_CHECK(VHostSCSICommon, (obj), TYPE_VHOST_SCSI_COMMON) + +typedef struct VHostSCSICommon { + VirtIOSCSICommon parent_obj; + + Error *migration_blocker; + + struct vhost_dev dev; + const int *feature_bits; + int32_t bootindex; + int channel; + int target; + int lun; +} VHostSCSICommon; + +int vhost_scsi_common_start(VHostSCSICommon *vsc); +void vhost_scsi_common_stop(VHostSCSICommon *vsc); +char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus, + DeviceState *dev); +void vhost_scsi_common_set_config(VirtIODevice *vdev, const uint8_t *config); +uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp); + +#endif /* VHOST_SCSI_COMMON_H */ diff --git a/include/hw/virtio/vhost-scsi.h b/include/hw/virtio/vhost-scsi.h index 9fd63df..04658d1 100644 --- a/include/hw/virtio/vhost-scsi.h +++ b/include/hw/virtio/vhost-scsi.h @@ -18,6 +18,7 @@ #include "hw/qdev.h" #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-scsi-common.h" enum vhost_scsi_vq_list { VHOST_SCSI_VQ_CONTROL = 0, @@ -30,15 +31,7 @@ enum vhost_scsi_vq_list { OBJECT_CHECK(VHostSCSI, (obj), TYPE_VHOST_SCSI) typedef struct VHostSCSI { - VirtIOSCSICommon parent_obj; - - Error *migration_blocker; - - struct vhost_dev dev; - int32_t bootindex; - int channel; - int target; - int lun; + VHostSCSICommon parent_obj; } VHostSCSI; #endif diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 8c8453c..eac2013 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -49,8 +49,10 @@ struct VirtIOSCSIConf { uint32_t num_queues; uint32_t max_sectors; uint32_t cmd_per_lun; +#ifdef CONFIG_VHOST_SCSI char *vhostfd; char *wwpn; +#endif uint32_t boot_tpgt; IOThread *iothread; }; diff --git a/include/migration/cpu.h b/include/migration/cpu.h index f3d5dfc..a40bd35 100644 --- a/include/migration/cpu.h +++ b/include/migration/cpu.h @@ -18,6 +18,8 @@ VMSTATE_UINT64_EQUAL_V(_f, _s, _v) #define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) +#define VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, _v) \ + VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, _v) #define VMSTATE_UINTTL_TEST(_f, _s, _t) \ VMSTATE_UINT64_TEST(_f, _s, _t) #define vmstate_info_uinttl vmstate_info_uint64 @@ -37,6 +39,8 @@ VMSTATE_UINT32_EQUAL_V(_f, _s, _v) #define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) +#define VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, _v) \ + VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, _v) #define VMSTATE_UINTTL_TEST(_f, _s, _t) \ VMSTATE_UINT32_TEST(_f, _s, _t) #define vmstate_info_uinttl vmstate_info_uint32 @@ -48,5 +52,8 @@ VMSTATE_UINTTL_EQUAL_V(_f, _s, 0) #define VMSTATE_UINTTL_ARRAY(_f, _s, _n) \ VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0) +#define VMSTATE_UINTTL_2DARRAY(_f, _s, _n1, _n2) \ + VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, 0) + #endif diff --git a/include/migration/migration.h b/include/migration/migration.h index ba1a16c..e29cb01 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -266,7 +266,8 @@ uint64_t xbzrle_mig_pages_cache_miss(void); double xbzrle_mig_cache_miss_rate(void); void ram_handle_compressed(void *host, uint8_t ch, uint64_t size); -void ram_debug_dump_bitmap(unsigned long *todump, bool expected); +void ram_debug_dump_bitmap(unsigned long *todump, bool expected, + unsigned long pages); /* For outgoing discard bitmap */ int ram_postcopy_send_discard_bitmap(MigrationState *ms); /* For incoming postcopy discard */ diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index dad3984..f4bf3f1 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -500,6 +500,19 @@ extern const VMStateInfo vmstate_info_qtailq; .offset = vmstate_offset_array(_state, _field, _type, _num),\ } +#define VMSTATE_STRUCT_2DARRAY_TEST(_field, _state, _n1, _n2, _test, \ + _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .num = (_n1) * (_n2), \ + .field_exists = (_test), \ + .version_id = (_version), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT | VMS_ARRAY, \ + .offset = vmstate_offset_2darray(_state, _field, _type, \ + _n1, _n2), \ +} + #define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \ .name = (stringify(_field)), \ .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \ @@ -747,6 +760,11 @@ extern const VMStateInfo vmstate_info_qtailq; VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, \ _vmsd, _type) +#define VMSTATE_STRUCT_2DARRAY(_field, _state, _n1, _n2, _version, \ + _vmsd, _type) \ + VMSTATE_STRUCT_2DARRAY_TEST(_field, _state, _n1, _n2, NULL, \ + _version, _vmsd, _type) + #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) \ VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _state, NULL, _version, _info, \ _size) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 18e6100..340e5fd 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -82,7 +82,9 @@ int:(x) ? -1 : 1; \ } -#ifdef __COUNTER__ +#if defined(CONFIG_STATIC_ASSERT) +#define QEMU_BUILD_BUG_ON(x) _Static_assert(!(x), "not expecting: " #x) +#elif defined(__COUNTER__) #define QEMU_BUILD_BUG_ON(x) typedef QEMU_BUILD_BUG_ON_STRUCT(x) \ glue(qemu_build_bug_on__, __COUNTER__) __attribute__((unused)) #else diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 450881d..fffc0f4 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -7,6 +7,14 @@ #include "qemu/bitmap.h" #include "qom/object.h" +#define IAC_EOR 239 +#define IAC_SE 240 +#define IAC_NOP 241 +#define IAC_BREAK 243 +#define IAC_IP 244 +#define IAC_SB 250 +#define IAC 255 + /* character device */ typedef enum { @@ -93,9 +101,8 @@ struct Chardev { char *filename; int logfd; int be_open; - guint fd_in_tag; + GSource *gsource; DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST); - QTAILQ_ENTRY(Chardev) next; }; /** @@ -171,14 +178,6 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp); Chardev *qemu_chr_new_noreplay(const char *label, const char *filename); /** - * @qemu_chr_delete: - * - * Destroy a character backend and remove it from the list of - * identified character backends. - */ -void qemu_chr_delete(Chardev *chr); - -/** * @qemu_chr_fe_set_echo: * * Ask the backend to override its normal echo setting. This only really @@ -427,7 +426,6 @@ void qemu_chr_fe_set_handlers(CharBackend *b, */ void qemu_chr_fe_take_focus(CharBackend *b); -void qemu_chr_be_generic_open(Chardev *s); void qemu_chr_fe_accept_input(CharBackend *be); int qemu_chr_add_client(Chardev *s, int fd); Chardev *qemu_chr_find(const char *name); diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index ef931be..2672a15 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -157,6 +157,7 @@ typedef struct DumpState { uint32_t sh_info; bool have_section; bool resume; + bool detached; ssize_t note_size; hwaddr memory_offset; int fd; diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 16175f7..15656b7 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -75,11 +75,8 @@ void qemu_remove_exit_notifier(Notifier *notify); void qemu_add_machine_init_done_notifier(Notifier *notify); void qemu_remove_machine_init_done_notifier(Notifier *notify); -void hmp_savevm(Monitor *mon, const QDict *qdict); -int save_vmstate(Monitor *mon, const char *name); +int save_vmstate(const char *name); int load_vmstate(const char *name); -void hmp_delvm(Monitor *mon, const QDict *qdict); -void hmp_info_snapshots(Monitor *mon, const QDict *qdict); void qemu_announce_self(void); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f520d77..ce77317 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1052,7 +1052,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, int i; for (i = 0; i < 32; i++) { - (*regs)[i] = tswapreg(env->gpr[i]); + (*regs)[i] = tswapreg(cpu_get_gpr(env, i)); } (*regs)[32] = tswapreg(env->pc); (*regs)[33] = tswapreg(cpu_get_sr(env)); diff --git a/linux-user/main.c b/linux-user/main.c index 10a3bb3..79d621b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2590,17 +2590,17 @@ void cpu_loop(CPUOpenRISCState *env) case EXCP_SYSCALL: env->pc += 4; /* 0xc00; */ ret = do_syscall(env, - env->gpr[11], /* return value */ - env->gpr[3], /* r3 - r7 are params */ - env->gpr[4], - env->gpr[5], - env->gpr[6], - env->gpr[7], - env->gpr[8], 0, 0); + cpu_get_gpr(env, 11), /* return value */ + cpu_get_gpr(env, 3), /* r3 - r7 are params */ + cpu_get_gpr(env, 4), + cpu_get_gpr(env, 5), + cpu_get_gpr(env, 6), + cpu_get_gpr(env, 7), + cpu_get_gpr(env, 8), 0, 0); if (ret == -TARGET_ERESTARTSYS) { env->pc -= 4; } else if (ret != -TARGET_QEMU_ESIGRETURN) { - env->gpr[11] = ret; + cpu_set_gpr(env, 11, ret); } break; case EXCP_DPF: @@ -4765,7 +4765,7 @@ int main(int argc, char **argv, char **envp) int i; for (i = 0; i < 32; i++) { - env->gpr[i] = regs->gpr[i]; + cpu_set_gpr(env, i, regs->gpr[i]); } env->pc = regs->pc; cpu_set_sr(env, regs->sr); diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h index f283d96..606ad6f 100644 --- a/linux-user/openrisc/target_cpu.h +++ b/linux-user/openrisc/target_cpu.h @@ -23,14 +23,14 @@ static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp) { if (newsp) { - env->gpr[1] = newsp; + cpu_set_gpr(env, 1, newsp); } - env->gpr[11] = 0; + cpu_set_gpr(env, 11, 0); } static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls) { - env->gpr[10] = newtls; + cpu_set_gpr(env, 10, newtls); } #endif diff --git a/linux-user/openrisc/target_signal.h b/linux-user/openrisc/target_signal.h index 9f2c493..95a733e 100644 --- a/linux-user/openrisc/target_signal.h +++ b/linux-user/openrisc/target_signal.h @@ -20,7 +20,7 @@ typedef struct target_sigaltstack { static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state) { - return state->gpr[1]; + return cpu_get_gpr(state, 1); } diff --git a/linux-user/signal.c b/linux-user/signal.c index a67db04..3d18d1b 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4411,7 +4411,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUOpenRISCState *regs, unsigned long mask) { - unsigned long usp = regs->gpr[1]; + unsigned long usp = cpu_get_gpr(regs, 1); /* copy the regs. they are first in sc so we can use sc directly */ @@ -4436,7 +4436,7 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUOpenRISCState *regs, size_t frame_size) { - unsigned long sp = regs->gpr[1]; + unsigned long sp = cpu_get_gpr(regs, 1); int onsigstack = on_sig_stack(sp); /* redzone */ @@ -4489,7 +4489,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(0, &frame->uc.tuc_link); __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags); + __put_user(sas_ss_flags(cpu_get_gpr(env, 1)), + &frame->uc.tuc_stack.ss_flags); __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); setup_sigcontext(&frame->sc, env, set->sig[0]); @@ -4512,13 +4513,13 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler */ env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */ - env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */ - env->gpr[3] = (unsigned long)sig; /* arg 1: signo */ - env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */ - env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */ + cpu_set_gpr(env, 9, (unsigned long)return_ip); /* what we enter LATER */ + cpu_set_gpr(env, 3, (unsigned long)sig); /* arg 1: signo */ + cpu_set_gpr(env, 4, (unsigned long)&frame->info); /* arg 2: (siginfo_t*) */ + cpu_set_gpr(env, 5, (unsigned long)&frame->uc); /* arg 3: ucontext */ /* actually move the usp to reflect the stacked frame */ - env->gpr[1] = (unsigned long)frame; + cpu_set_gpr(env, 1, (unsigned long)frame); return; diff --git a/migration/exec.c b/migration/exec.c index 9157721..aba9089 100644 --- a/migration/exec.c +++ b/migration/exec.c @@ -32,7 +32,7 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error trace_migration_exec_outgoing(command); ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv, - O_WRONLY, + O_RDWR, errp)); if (!ioc) { return; @@ -59,7 +59,7 @@ void exec_start_incoming_migration(const char *command, Error **errp) trace_migration_exec_incoming(command); ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv, - O_RDONLY, + O_RDWR, errp)); if (!ioc) { return; diff --git a/migration/migration.c b/migration/migration.c index 353f272..799952c 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -26,7 +26,7 @@ #include "qemu/sockets.h" #include "qemu/rcu.h" #include "migration/block.h" -#include "migration/postcopy-ram.h" +#include "postcopy-ram.h" #include "qemu/thread.h" #include "qmp-commands.h" #include "trace.h" diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 85fd8d7..cdadaf6 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -20,7 +20,7 @@ #include "qemu-common.h" #include "migration/migration.h" -#include "migration/postcopy-ram.h" +#include "postcopy-ram.h" #include "sysemu/sysemu.h" #include "sysemu/balloon.h" #include "qemu/error-report.h" @@ -33,7 +33,6 @@ struct PostcopyDiscardState { const char *ramblock_name; - uint64_t offset; /* Bitmap entry for the 1st bit of this RAMBlock */ uint16_t cur_entry; /* * Start and length of a discard range (bytes) @@ -717,14 +716,12 @@ void *postcopy_get_tmp_page(MigrationIncomingState *mis) * returns: a new PDS. */ PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms, - unsigned long offset, const char *name) { PostcopyDiscardState *res = g_malloc0(sizeof(PostcopyDiscardState)); if (res) { res->ramblock_name = name; - res->offset = offset; } return res; @@ -745,7 +742,7 @@ void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds, { size_t tp_size = qemu_target_page_size(); /* Convert to byte offsets within the RAM block */ - pds->start_list[pds->cur_entry] = (start - pds->offset) * tp_size; + pds->start_list[pds->cur_entry] = start * tp_size; pds->length_list[pds->cur_entry] = length * tp_size; trace_postcopy_discard_send_range(pds->ramblock_name, start, length); pds->cur_entry++; diff --git a/include/migration/postcopy-ram.h b/migration/postcopy-ram.h index 8e036b9..4c25f03 100644 --- a/include/migration/postcopy-ram.h +++ b/migration/postcopy-ram.h @@ -43,12 +43,9 @@ int postcopy_ram_prepare_discard(MigrationIncomingState *mis); /* * Called at the start of each RAMBlock by the bitmap code. - * 'offset' is the bitmap offset of the named RAMBlock in the migration - * bitmap. * Returns a new PDS */ PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms, - unsigned long offset, const char *name); /* diff --git a/migration/ram.c b/migration/ram.c index f48664e..293d27c 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -36,7 +36,7 @@ #include "qemu/timer.h" #include "qemu/main-loop.h" #include "migration/migration.h" -#include "migration/postcopy-ram.h" +#include "postcopy-ram.h" #include "exec/address-spaces.h" #include "migration/page_cache.h" #include "qemu/error-report.h" @@ -138,19 +138,6 @@ out: return ret; } -struct RAMBitmap { - struct rcu_head rcu; - /* Main migration bitmap */ - unsigned long *bmap; - /* bitmap of pages that haven't been sent even once - * only maintained and used in postcopy at the moment - * where it's used to send the dirtymap at the start - * of the postcopy phase - */ - unsigned long *unsentmap; -}; -typedef struct RAMBitmap RAMBitmap; - /* * An outstanding page request, on the source, having been received * and queued @@ -220,8 +207,6 @@ struct RAMState { uint64_t postcopy_requests; /* protects modification of the bitmap */ QemuMutex bitmap_mutex; - /* Ram Bitmap protected by RCU */ - RAMBitmap *ram_bitmap; /* The RAMBlock used in the last src_page_requests */ RAMBlock *last_req_rb; /* Queue of outstanding page requests from the destination */ @@ -614,22 +599,17 @@ static inline unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb, unsigned long start) { - unsigned long base = rb->offset >> TARGET_PAGE_BITS; - unsigned long nr = base + start; - uint64_t rb_size = rb->used_length; - unsigned long size = base + (rb_size >> TARGET_PAGE_BITS); - unsigned long *bitmap; - + unsigned long size = rb->used_length >> TARGET_PAGE_BITS; + unsigned long *bitmap = rb->bmap; unsigned long next; - bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap; - if (rs->ram_bulk_stage && nr > base) { - next = nr + 1; + if (rs->ram_bulk_stage && start > 0) { + next = start + 1; } else { - next = find_next_bit(bitmap, size, nr); + next = find_next_bit(bitmap, size, start); } - return next - base; + return next; } static inline bool migration_bitmap_clear_dirty(RAMState *rs, @@ -637,10 +617,8 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, unsigned long page) { bool ret; - unsigned long *bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap; - unsigned long nr = (rb->offset >> TARGET_PAGE_BITS) + page; - ret = test_and_clear_bit(nr, bitmap); + ret = test_and_clear_bit(page, rb->bmap); if (ret) { rs->migration_dirty_pages--; @@ -651,10 +629,8 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb, ram_addr_t start, ram_addr_t length) { - unsigned long *bitmap; - bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap; rs->migration_dirty_pages += - cpu_physical_memory_sync_dirty_bitmap(bitmap, rb, start, length, + cpu_physical_memory_sync_dirty_bitmap(rb, start, length, &rs->num_dirty_pages_period); } @@ -812,6 +788,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) ram_addr_t offset = pss->page << TARGET_PAGE_BITS; p = block->host + offset; + trace_ram_save_page(block->idstr, (uint64_t)offset, p); /* In doubt sent page as normal */ bytes_xmit = 0; @@ -1153,17 +1130,13 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss) * search already sent it. */ if (block) { - unsigned long *bitmap; unsigned long page; - bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap; - page = (block->offset + offset) >> TARGET_PAGE_BITS; - dirty = test_bit(page, bitmap); + page = offset >> TARGET_PAGE_BITS; + dirty = test_bit(page, block->bmap); if (!dirty) { trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset, - page, - test_bit(page, - atomic_rcu_read(&rs->ram_bitmap)->unsentmap)); + page, test_bit(page, block->unsentmap)); } else { trace_get_queued_page(block->idstr, (uint64_t)offset, page); } @@ -1301,16 +1274,13 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, /* Check the pages is dirty and if it is send it */ if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { - unsigned long *unsentmap; /* * If xbzrle is on, stop using the data compression after first * round of migration even if compression is enabled. In theory, * xbzrle can do better than compression. */ - unsigned long page = - (pss->block->offset >> TARGET_PAGE_BITS) + pss->page; - if (migrate_use_compression() - && (rs->ram_bulk_stage || !migrate_use_xbzrle())) { + if (migrate_use_compression() && + (rs->ram_bulk_stage || !migrate_use_xbzrle())) { res = ram_save_compressed_page(rs, pss, last_stage); } else { res = ram_save_page(rs, pss, last_stage); @@ -1319,9 +1289,8 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, if (res < 0) { return res; } - unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap; - if (unsentmap) { - clear_bit(page, unsentmap); + if (pss->block->unsentmap) { + clear_bit(pss->page, pss->block->unsentmap); } } @@ -1451,25 +1420,20 @@ void free_xbzrle_decoded_buf(void) xbzrle_decoded_buf = NULL; } -static void migration_bitmap_free(RAMBitmap *bmap) -{ - g_free(bmap->bmap); - g_free(bmap->unsentmap); - g_free(bmap); -} - static void ram_migration_cleanup(void *opaque) { - RAMState *rs = opaque; + RAMBlock *block; /* caller have hold iothread lock or is in a bh, so there is * no writing race against this migration_bitmap */ - RAMBitmap *bitmap = rs->ram_bitmap; - atomic_rcu_set(&rs->ram_bitmap, NULL); - if (bitmap) { - memory_global_dirty_log_stop(); - call_rcu(bitmap, migration_bitmap_free, rcu); + memory_global_dirty_log_stop(); + + QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { + g_free(block->bmap); + block->bmap = NULL; + g_free(block->unsentmap); + block->unsentmap = NULL; } XBZRLE_cache_lock(); @@ -1501,27 +1465,22 @@ static void ram_state_reset(RAMState *rs) * of; it won't bother printing lines that are all this value. * If 'todump' is null the migration bitmap is dumped. */ -void ram_debug_dump_bitmap(unsigned long *todump, bool expected) +void ram_debug_dump_bitmap(unsigned long *todump, bool expected, + unsigned long pages) { - unsigned long ram_pages = last_ram_page(); - RAMState *rs = &ram_state; int64_t cur; int64_t linelen = 128; char linebuf[129]; - if (!todump) { - todump = atomic_rcu_read(&rs->ram_bitmap)->bmap; - } - - for (cur = 0; cur < ram_pages; cur += linelen) { + for (cur = 0; cur < pages; cur += linelen) { int64_t curb; bool found = false; /* * Last line; catch the case where the line length * is longer than remaining ram */ - if (cur + linelen > ram_pages) { - linelen = ram_pages - cur; + if (cur + linelen > pages) { + linelen = pages - cur; } for (curb = 0; curb < linelen; curb++) { bool thisbit = test_bit(cur + curb, todump); @@ -1539,14 +1498,12 @@ void ram_debug_dump_bitmap(unsigned long *todump, bool expected) void ram_postcopy_migrated_memory_release(MigrationState *ms) { - RAMState *rs = &ram_state; struct RAMBlock *block; - unsigned long *bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap; QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { - unsigned long first = block->offset >> TARGET_PAGE_BITS; - unsigned long range = first + (block->used_length >> TARGET_PAGE_BITS); - unsigned long run_start = find_next_zero_bit(bitmap, range, first); + unsigned long *bitmap = block->bmap; + unsigned long range = block->used_length >> TARGET_PAGE_BITS; + unsigned long run_start = find_next_zero_bit(bitmap, range, 0); while (run_start < range) { unsigned long run_end = find_next_bit(bitmap, range, run_start + 1); @@ -1573,16 +1530,13 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms) */ static int postcopy_send_discard_bm_ram(MigrationState *ms, PostcopyDiscardState *pds, - unsigned long start, - unsigned long length) + RAMBlock *block) { - RAMState *rs = &ram_state; - unsigned long end = start + length; /* one after the end */ + unsigned long end = block->used_length >> TARGET_PAGE_BITS; unsigned long current; - unsigned long *unsentmap; + unsigned long *unsentmap = block->unsentmap; - unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap; - for (current = start; current < end; ) { + for (current = 0; current < end; ) { unsigned long one = find_next_bit(unsentmap, end, current); if (one <= end) { @@ -1625,18 +1579,15 @@ static int postcopy_each_ram_send_discard(MigrationState *ms) int ret; QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { - unsigned long first = block->offset >> TARGET_PAGE_BITS; - PostcopyDiscardState *pds = postcopy_discard_send_init(ms, - first, - block->idstr); + PostcopyDiscardState *pds = + postcopy_discard_send_init(ms, block->idstr); /* * Postcopy sends chunks of bitmap over the wire, but it * just needs indexes at this point, avoids it having * target page specific code. */ - ret = postcopy_send_discard_bm_ram(ms, pds, first, - block->used_length >> TARGET_PAGE_BITS); + ret = postcopy_send_discard_bm_ram(ms, pds, block); postcopy_discard_send_finish(ms, pds); if (ret) { return ret; @@ -1667,12 +1618,10 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, PostcopyDiscardState *pds) { RAMState *rs = &ram_state; - unsigned long *bitmap; - unsigned long *unsentmap; + unsigned long *bitmap = block->bmap; + unsigned long *unsentmap = block->unsentmap; unsigned int host_ratio = block->page_size / TARGET_PAGE_SIZE; - unsigned long first = block->offset >> TARGET_PAGE_BITS; - unsigned long len = block->used_length >> TARGET_PAGE_BITS; - unsigned long last = first + (len - 1); + unsigned long pages = block->used_length >> TARGET_PAGE_BITS; unsigned long run_start; if (block->page_size == TARGET_PAGE_SIZE) { @@ -1680,18 +1629,15 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, return; } - bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap; - unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap; - if (unsent_pass) { /* Find a sent page */ - run_start = find_next_zero_bit(unsentmap, last + 1, first); + run_start = find_next_zero_bit(unsentmap, pages, 0); } else { /* Find a dirty page */ - run_start = find_next_bit(bitmap, last + 1, first); + run_start = find_next_bit(bitmap, pages, 0); } - while (run_start <= last) { + while (run_start < pages) { bool do_fixup = false; unsigned long fixup_start_addr; unsigned long host_offset; @@ -1711,9 +1657,9 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, /* Find the end of this run */ unsigned long run_end; if (unsent_pass) { - run_end = find_next_bit(unsentmap, last + 1, run_start + 1); + run_end = find_next_bit(unsentmap, pages, run_start + 1); } else { - run_end = find_next_zero_bit(bitmap, last + 1, run_start + 1); + run_end = find_next_zero_bit(bitmap, pages, run_start + 1); } /* * If the end isn't at the start of a host page, then the @@ -1770,11 +1716,10 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, if (unsent_pass) { /* Find the next sent page for the next iteration */ - run_start = find_next_zero_bit(unsentmap, last + 1, - run_start); + run_start = find_next_zero_bit(unsentmap, pages, run_start); } else { /* Find the next dirty page for the next iteration */ - run_start = find_next_bit(bitmap, last + 1, run_start); + run_start = find_next_bit(bitmap, pages, run_start); } } } @@ -1791,34 +1736,22 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, * Returns zero on success * * @ms: current migration state + * @block: block we want to work with */ -static int postcopy_chunk_hostpages(MigrationState *ms) +static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block) { - RAMState *rs = &ram_state; - struct RAMBlock *block; - - /* Easiest way to make sure we don't resume in the middle of a host-page */ - rs->last_seen_block = NULL; - rs->last_sent_block = NULL; - rs->last_page = 0; - - QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { - unsigned long first = block->offset >> TARGET_PAGE_BITS; - - PostcopyDiscardState *pds = - postcopy_discard_send_init(ms, first, block->idstr); - - /* First pass: Discard all partially sent host pages */ - postcopy_chunk_hostpages_pass(ms, true, block, pds); - /* - * Second pass: Ensure that all partially dirty host pages are made - * fully dirty. - */ - postcopy_chunk_hostpages_pass(ms, false, block, pds); + PostcopyDiscardState *pds = + postcopy_discard_send_init(ms, block->idstr); - postcopy_discard_send_finish(ms, pds); - } /* ram_list loop */ + /* First pass: Discard all partially sent host pages */ + postcopy_chunk_hostpages_pass(ms, true, block, pds); + /* + * Second pass: Ensure that all partially dirty host pages are made + * fully dirty. + */ + postcopy_chunk_hostpages_pass(ms, false, block, pds); + postcopy_discard_send_finish(ms, pds); return 0; } @@ -1840,43 +1773,49 @@ static int postcopy_chunk_hostpages(MigrationState *ms) int ram_postcopy_send_discard_bitmap(MigrationState *ms) { RAMState *rs = &ram_state; + RAMBlock *block; int ret; - unsigned long *bitmap, *unsentmap; rcu_read_lock(); /* This should be our last sync, the src is now paused */ migration_bitmap_sync(rs); - unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap; - if (!unsentmap) { - /* We don't have a safe way to resize the sentmap, so - * if the bitmap was resized it will be NULL at this - * point. - */ - error_report("migration ram resized during precopy phase"); - rcu_read_unlock(); - return -EINVAL; - } - - /* Deal with TPS != HPS and huge pages */ - ret = postcopy_chunk_hostpages(ms); - if (ret) { - rcu_read_unlock(); - return ret; - } - - /* - * Update the unsentmap to be unsentmap = unsentmap | dirty - */ - bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap; - bitmap_or(unsentmap, unsentmap, bitmap, last_ram_page()); + /* Easiest way to make sure we don't resume in the middle of a host-page */ + rs->last_seen_block = NULL; + rs->last_sent_block = NULL; + rs->last_page = 0; + QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { + unsigned long pages = block->used_length >> TARGET_PAGE_BITS; + unsigned long *bitmap = block->bmap; + unsigned long *unsentmap = block->unsentmap; + + if (!unsentmap) { + /* We don't have a safe way to resize the sentmap, so + * if the bitmap was resized it will be NULL at this + * point. + */ + error_report("migration ram resized during precopy phase"); + rcu_read_unlock(); + return -EINVAL; + } + /* Deal with TPS != HPS and huge pages */ + ret = postcopy_chunk_hostpages(ms, block); + if (ret) { + rcu_read_unlock(); + return ret; + } - trace_ram_postcopy_send_discard_bitmap(); + /* + * Update the unsentmap to be unsentmap = unsentmap | dirty + */ + bitmap_or(unsentmap, unsentmap, bitmap, pages); #ifdef DEBUG_POSTCOPY - ram_debug_dump_bitmap(unsentmap, true); + ram_debug_dump_bitmap(unsentmap, true, pages); #endif + } + trace_ram_postcopy_send_discard_bitmap(); ret = postcopy_each_ram_send_discard(ms); rcu_read_unlock(); @@ -1918,8 +1857,6 @@ err: static int ram_state_init(RAMState *rs) { - unsigned long ram_bitmap_pages; - memset(rs, 0, sizeof(*rs)); qemu_mutex_init(&rs->bitmap_mutex); qemu_mutex_init(&rs->src_page_req_mutex); @@ -1961,16 +1898,19 @@ static int ram_state_init(RAMState *rs) rcu_read_lock(); ram_state_reset(rs); - rs->ram_bitmap = g_new0(RAMBitmap, 1); /* Skip setting bitmap if there is no RAM */ if (ram_bytes_total()) { - ram_bitmap_pages = last_ram_page(); - rs->ram_bitmap->bmap = bitmap_new(ram_bitmap_pages); - bitmap_set(rs->ram_bitmap->bmap, 0, ram_bitmap_pages); + RAMBlock *block; - if (migrate_postcopy_ram()) { - rs->ram_bitmap->unsentmap = bitmap_new(ram_bitmap_pages); - bitmap_set(rs->ram_bitmap->unsentmap, 0, ram_bitmap_pages); + QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { + unsigned long pages = block->max_length >> TARGET_PAGE_BITS; + + block->bmap = bitmap_new(pages); + bitmap_set(block->bmap, 0, pages); + if (migrate_postcopy_ram()) { + block->unsentmap = bitmap_new(pages); + bitmap_set(block->unsentmap, 0, pages); + } } } @@ -2611,6 +2551,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) ret = -EINVAL; break; } + trace_ram_load_loop(block->idstr, (uint64_t)addr, flags, host); } switch (flags & ~RAM_SAVE_FLAG_CONTINUE) { diff --git a/migration/savevm.c b/migration/savevm.c index a00c1ab..352a8f2 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -33,15 +33,12 @@ #include "hw/qdev.h" #include "hw/xen/xen.h" #include "net/net.h" -#include "monitor/monitor.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" -#include "audio/audio.h" #include "migration/migration.h" -#include "migration/postcopy-ram.h" +#include "postcopy-ram.h" #include "qapi/qmp/qerror.h" #include "qemu/error-report.h" -#include "qemu/sockets.h" #include "qemu/queue.h" #include "sysemu/cpus.h" #include "exec/memory.h" @@ -50,7 +47,6 @@ #include "qemu/bitops.h" #include "qemu/iov.h" #include "block/snapshot.h" -#include "block/qapi.h" #include "qemu/cutils.h" #include "io/channel-buffer.h" #include "io/channel-file.h" @@ -2078,7 +2074,7 @@ int qemu_loadvm_state(QEMUFile *f) return ret; } -int save_vmstate(Monitor *mon, const char *name) +int save_vmstate(const char *name) { BlockDriverState *bs, *bs1; QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; @@ -2092,8 +2088,8 @@ int save_vmstate(Monitor *mon, const char *name) AioContext *aio_context; if (!bdrv_all_can_snapshot(&bs)) { - monitor_printf(mon, "Device '%s' is writable but does not " - "support snapshots.\n", bdrv_get_device_name(bs)); + error_report("Device '%s' is writable but does not support snapshots", + bdrv_get_device_name(bs)); return ret; } @@ -2110,7 +2106,7 @@ int save_vmstate(Monitor *mon, const char *name) bs = bdrv_all_find_vmstate_bs(); if (bs == NULL) { - monitor_printf(mon, "No block device can accept snapshots\n"); + error_report("No block device can accept snapshots"); return ret; } aio_context = bdrv_get_aio_context(bs); @@ -2119,7 +2115,7 @@ int save_vmstate(Monitor *mon, const char *name) ret = global_state_store(); if (ret) { - monitor_printf(mon, "Error saving global state\n"); + error_report("Error saving global state"); return ret; } vm_stop(RUN_STATE_SAVE_VM); @@ -2151,7 +2147,7 @@ int save_vmstate(Monitor *mon, const char *name) /* save the VM state */ f = qemu_fopen_bdrv(bs, 1); if (!f) { - monitor_printf(mon, "Could not open VM state file\n"); + error_report("Could not open VM state file"); goto the_end; } ret = qemu_savevm_state(f, &local_err); @@ -2164,8 +2160,8 @@ int save_vmstate(Monitor *mon, const char *name) ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, &bs); if (ret < 0) { - monitor_printf(mon, "Error while creating snapshot on '%s'\n", - bdrv_get_device_name(bs)); + error_report("Error while creating snapshot on '%s'", + bdrv_get_device_name(bs)); goto the_end; } @@ -2179,11 +2175,6 @@ int save_vmstate(Monitor *mon, const char *name) return ret; } -void hmp_savevm(Monitor *mon, const QDict *qdict) -{ - save_vmstate(mon, qdict_get_try_str(qdict, "name")); -} - void qmp_xen_save_devices_state(const char *filename, Error **errp) { QEMUFile *f; @@ -2253,7 +2244,7 @@ int load_vmstate(const char *name) MigrationIncomingState *mis = migration_incoming_get_current(); if (!bdrv_all_can_snapshot(&bs)) { - error_report("Device '%s' is writable but does not support snapshots.", + error_report("Device '%s' is writable but does not support snapshots", bdrv_get_device_name(bs)); return -ENOTSUP; } @@ -2317,162 +2308,6 @@ int load_vmstate(const char *name) return 0; } -void hmp_delvm(Monitor *mon, const QDict *qdict) -{ - BlockDriverState *bs; - Error *err; - const char *name = qdict_get_str(qdict, "name"); - - if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) { - error_reportf_err(err, - "Error while deleting snapshot on device '%s': ", - bdrv_get_device_name(bs)); - } -} - -void hmp_info_snapshots(Monitor *mon, const QDict *qdict) -{ - BlockDriverState *bs, *bs1; - BdrvNextIterator it1; - QEMUSnapshotInfo *sn_tab, *sn; - bool no_snapshot = true; - int nb_sns, i; - int total; - int *global_snapshots; - AioContext *aio_context; - - typedef struct SnapshotEntry { - QEMUSnapshotInfo sn; - QTAILQ_ENTRY(SnapshotEntry) next; - } SnapshotEntry; - - typedef struct ImageEntry { - const char *imagename; - QTAILQ_ENTRY(ImageEntry) next; - QTAILQ_HEAD(, SnapshotEntry) snapshots; - } ImageEntry; - - QTAILQ_HEAD(, ImageEntry) image_list = - QTAILQ_HEAD_INITIALIZER(image_list); - - ImageEntry *image_entry, *next_ie; - SnapshotEntry *snapshot_entry; - - bs = bdrv_all_find_vmstate_bs(); - if (!bs) { - monitor_printf(mon, "No available block device supports snapshots\n"); - return; - } - aio_context = bdrv_get_aio_context(bs); - - aio_context_acquire(aio_context); - nb_sns = bdrv_snapshot_list(bs, &sn_tab); - aio_context_release(aio_context); - - if (nb_sns < 0) { - monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns); - return; - } - - for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) { - int bs1_nb_sns = 0; - ImageEntry *ie; - SnapshotEntry *se; - AioContext *ctx = bdrv_get_aio_context(bs1); - - aio_context_acquire(ctx); - if (bdrv_can_snapshot(bs1)) { - sn = NULL; - bs1_nb_sns = bdrv_snapshot_list(bs1, &sn); - if (bs1_nb_sns > 0) { - no_snapshot = false; - ie = g_new0(ImageEntry, 1); - ie->imagename = bdrv_get_device_name(bs1); - QTAILQ_INIT(&ie->snapshots); - QTAILQ_INSERT_TAIL(&image_list, ie, next); - for (i = 0; i < bs1_nb_sns; i++) { - se = g_new0(SnapshotEntry, 1); - se->sn = sn[i]; - QTAILQ_INSERT_TAIL(&ie->snapshots, se, next); - } - } - g_free(sn); - } - aio_context_release(ctx); - } - - if (no_snapshot) { - monitor_printf(mon, "There is no snapshot available.\n"); - return; - } - - global_snapshots = g_new0(int, nb_sns); - total = 0; - for (i = 0; i < nb_sns; i++) { - SnapshotEntry *next_sn; - if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) { - global_snapshots[total] = i; - total++; - QTAILQ_FOREACH(image_entry, &image_list, next) { - QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, - next, next_sn) { - if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) { - QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry, - next); - g_free(snapshot_entry); - } - } - } - } - } - - monitor_printf(mon, "List of snapshots present on all disks:\n"); - - if (total > 0) { - bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL); - monitor_printf(mon, "\n"); - for (i = 0; i < total; i++) { - sn = &sn_tab[global_snapshots[i]]; - /* The ID is not guaranteed to be the same on all images, so - * overwrite it. - */ - pstrcpy(sn->id_str, sizeof(sn->id_str), "--"); - bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn); - monitor_printf(mon, "\n"); - } - } else { - monitor_printf(mon, "None\n"); - } - - QTAILQ_FOREACH(image_entry, &image_list, next) { - if (QTAILQ_EMPTY(&image_entry->snapshots)) { - continue; - } - monitor_printf(mon, - "\nList of partial (non-loadable) snapshots on '%s':\n", - image_entry->imagename); - bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL); - monitor_printf(mon, "\n"); - QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) { - bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, - &snapshot_entry->sn); - monitor_printf(mon, "\n"); - } - } - - QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) { - SnapshotEntry *next_sn; - QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next, - next_sn) { - g_free(snapshot_entry); - } - g_free(image_entry); - } - g_free(sn_tab); - g_free(global_snapshots); - -} - void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev) { qemu_ram_set_idstr(mr->ram_block, diff --git a/migration/socket.c b/migration/socket.c index 13966f1..dc88812 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -79,7 +79,6 @@ static void socket_outgoing_migration(QIOTask *task, if (qio_task_propagate_error(task, &err)) { trace_migration_socket_outgoing_error(error_get_pretty(err)); - data->s->to_dst_file = NULL; migrate_fd_error(data->s, err); error_free(err); } else { diff --git a/migration/tls.c b/migration/tls.c index 45bec44..a33ecb7 100644 --- a/migration/tls.c +++ b/migration/tls.c @@ -116,7 +116,6 @@ static void migration_tls_outgoing_handshake(QIOTask *task, if (qio_task_propagate_error(task, &err)) { trace_migration_tls_outgoing_handshake_error(error_get_pretty(err)); - s->to_dst_file = NULL; migrate_fd_error(s, err); error_free(err); } else { diff --git a/migration/trace-events b/migration/trace-events index b8f01a2..5b8ccf3 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -69,8 +69,10 @@ migration_bitmap_sync_start(void) "" migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 migration_throttle(void) "" ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx" +ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: addr: %" PRIx64 " flags: %x host: %p" ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x" ram_postcopy_send_discard_bitmap(void) "" +ram_save_page(const char *rbname, uint64_t offset, void *host) "%s: offset: %" PRIx64 " host: %p" ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: %zx len: %zx" # migration/migration.c @@ -37,7 +37,6 @@ #include "net/slirp.h" #include "sysemu/char.h" #include "ui/qemu-spice.h" -#include "sysemu/sysemu.h" #include "sysemu/numa.h" #include "monitor/monitor.h" #include "qemu/config-file.h" @@ -1954,18 +1953,6 @@ void qmp_closefd(const char *fdname, Error **errp) error_setg(errp, QERR_FD_NOT_FOUND, fdname); } -static void hmp_loadvm(Monitor *mon, const QDict *qdict) -{ - int saved_vm_running = runstate_is_running(); - const char *name = qdict_get_str(qdict, "name"); - - vm_stop(RUN_STATE_RESTORE_VM); - - if (load_vmstate(name) == 0 && saved_vm_running) { - vm_start(); - } -} - int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) { mon_fd_t *monfd; diff --git a/net/vhost-user.c b/net/vhost-user.c index e7e6340..00a0c1c 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -154,7 +154,7 @@ static void vhost_user_cleanup(NetClientState *nc) Chardev *chr = qemu_chr_fe_get_driver(&s->chr); qemu_chr_fe_deinit(&s->chr); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); } qemu_purge_queued_packets(nc); diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img Binary files differindex 2a4adfa..0b01d49 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 0339c24..79a46b6 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) .PHONY : all clean build-all -OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o virtio-scsi.o +OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS)) QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index b21c877..523fa78 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -183,15 +183,21 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address) static void run_eckd_boot_script(block_number_t mbr_block_nr) { int i; + unsigned int loadparm = get_loadparm_index(); block_number_t block_nr; uint64_t address; - ScsiMbr *scsi_mbr = (void *)sec; + ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */ BootMapScript *bms = (void *)sec; + debug_print_int("loadparm", loadparm); + IPL_assert(loadparm < 31, "loadparm value greater than" + " maximum number of boot entries allowed"); + memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(mbr_block_nr, sec, "Cannot read MBR"); - block_nr = eckd_block_num((void *)&(scsi_mbr->blockptr)); + block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm])); + IPL_assert(block_nr != -1, "No Boot Map"); memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(block_nr, sec, "Cannot read Boot Map Script"); @@ -444,7 +450,8 @@ static void ipl_scsi(void) uint8_t *ns, *ns_end; int program_table_entries = 0; const int pte_len = sizeof(ScsiBlockPtr); - ScsiBlockPtr *prog_table_entry; + ScsiBlockPtr *prog_table_entry = NULL; + unsigned int loadparm = get_loadparm_index(); /* Grab the MBR */ memset(sec, FREE_SPACE_FILLER, sizeof(sec)); @@ -458,15 +465,16 @@ static void ipl_scsi(void) debug_print_int("MBR Version", mbr->version_id); IPL_check(mbr->version_id == 1, "Unknown MBR layout version, assuming version 1"); - debug_print_int("program table", mbr->blockptr.blockno); - IPL_assert(mbr->blockptr.blockno, "No Program Table"); + debug_print_int("program table", mbr->blockptr[0].blockno); + IPL_assert(mbr->blockptr[0].blockno, "No Program Table"); /* Parse the program table */ - read_block(mbr->blockptr.blockno, sec, + read_block(mbr->blockptr[0].blockno, sec, "Error reading Program Table"); IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT"); + debug_print_int("loadparm index", loadparm); ns_end = sec + virtio_get_block_size(); for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) { prog_table_entry = (ScsiBlockPtr *)ns; @@ -475,16 +483,15 @@ static void ipl_scsi(void) } program_table_entries++; + if (program_table_entries == loadparm + 1) { + break; /* selected entry found */ + } } debug_print_int("program table entries", program_table_entries); IPL_assert(program_table_entries != 0, "Empty Program Table"); - /* Run the default entry */ - - prog_table_entry = (ScsiBlockPtr *)(sec + pte_len); - zipl_run(prog_table_entry); /* no return */ } @@ -648,6 +655,7 @@ static IsoBcSection *find_iso_bc_entry(void) IsoBcEntry *e = (IsoBcEntry *)sec; uint32_t offset = find_iso_bc(); int i; + unsigned int loadparm = get_loadparm_index(); if (!offset) { return NULL; @@ -668,7 +676,11 @@ static IsoBcSection *find_iso_bc_entry(void) for (i = 1; i < ISO_BC_ENTRY_PER_SECTOR; i++) { if (e[i].id == ISO_BC_BOOTABLE_SECTION) { if (is_iso_bc_entry_compatible(&e[i].body.sect)) { - return &e[i].body.sect; + if (loadparm <= 1) { + /* found, default, or unspecified */ + return &e[i].body.sect; + } + loadparm--; } } } diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h index bea1687..7f36782 100644 --- a/pc-bios/s390-ccw/bootmap.h +++ b/pc-bios/s390-ccw/bootmap.h @@ -70,7 +70,7 @@ typedef struct ScsiMbr { uint8_t magic[4]; uint32_t version_id; uint8_t reserved[8]; - ScsiBlockPtr blockptr; + ScsiBlockPtr blockptr[]; } __attribute__ ((packed)) ScsiMbr; #define ZIPL_MAGIC "zIPL" @@ -264,28 +264,6 @@ typedef enum { /* utility code below */ -static const unsigned char ebc2asc[256] = - /* 0123456789abcdef0123456789abcdef */ - "................................" /* 1F */ - "................................" /* 3F */ - " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */ - "-/.........,%_>?.........`:#@'=\""/* 7F */ - ".abcdefghi.......jklmnopqr......" /* 9F */ - "..stuvwxyz......................" /* BF */ - ".ABCDEFGHI.......JKLMNOPQR......" /* DF */ - "..STUVWXYZ......0123456789......";/* FF */ - -static inline void ebcdic_to_ascii(const char *src, - char *dst, - unsigned int size) -{ - unsigned int i; - for (i = 0; i < size; i++) { - unsigned c = src[i]; - dst[i] = ebc2asc[c]; - } -} - static inline void print_volser(const void *volser) { char ascii[8]; diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 0946766..1cacc1b 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -14,6 +14,18 @@ char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); static SubChannelId blk_schid = { .one = 1 }; IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); +static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +const unsigned char ebc2asc[256] = + /* 0123456789abcdef0123456789abcdef */ + "................................" /* 1F */ + "................................" /* 3F */ + " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */ + "-/.........,%_>?.........`:#@'=\""/* 7F */ + ".abcdefghi.......jklmnopqr......" /* 9F */ + "..stuvwxyz......................" /* BF */ + ".ABCDEFGHI.......JKLMNOPQR......" /* DF */ + "..STUVWXYZ......0123456789......";/* FF */ /* * Priniciples of Operations (SA22-7832-09) chapter 17 requires that @@ -29,7 +41,6 @@ void write_subsystem_identification(void) *zeroes = 0; } - void panic(const char *string) { sclp_print(string); @@ -37,6 +48,26 @@ void panic(const char *string) while (1) { } } +unsigned int get_loadparm_index(void) +{ + const char *lp = loadparm; + int i; + unsigned int idx = 0; + + for (i = 0; i < 8; i++) { + char c = lp[i]; + + if (c < '0' || c > '9') { + break; + } + + idx *= 10; + idx += c - '0'; + } + + return idx; +} + static bool find_dev(Schib *schib, int dev_no) { int i, r; @@ -73,6 +104,7 @@ static void virtio_setup(void) int ssid; bool found = false; uint16_t dev_no; + char ldp[] = "LOADPARM=[________]\n"; VDev *vdev = virtio_get_device(); /* @@ -82,6 +114,10 @@ static void virtio_setup(void) */ enable_mss_facility(); + sclp_get_loadparm_ascii(loadparm); + memcpy(ldp + 10, loadparm, 8); + sclp_print(ldp); + if (store_iplb(&iplb)) { switch (iplb.pbt) { case S390_IPL_TYPE_CCW: diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index ded67bc..07d8cbc 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -62,10 +62,12 @@ void consume_sclp_int(void); void panic(const char *string); void write_subsystem_identification(void); extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); +unsigned int get_loadparm_index(void); -/* sclp-ascii.c */ +/* sclp.c */ void sclp_print(const char *string); void sclp_setup(void); +void sclp_get_loadparm_ascii(char *loadparm); /* virtio.c */ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, @@ -189,4 +191,17 @@ static inline void IPL_check(bool term, const char *message) } } +extern const unsigned char ebc2asc[256]; +static inline void ebcdic_to_ascii(const char *src, + char *dst, + unsigned int size) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + unsigned c = src[i]; + dst[i] = ebc2asc[c]; + } +} + #endif /* S390_CCW_H */ diff --git a/pc-bios/s390-ccw/sclp-ascii.c b/pc-bios/s390-ccw/sclp.c index dc1c3e4..a1639ba 100644 --- a/pc-bios/s390-ccw/sclp-ascii.c +++ b/pc-bios/s390-ccw/sclp.c @@ -80,3 +80,15 @@ void sclp_print(const char *str) sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); } + +void sclp_get_loadparm_ascii(char *loadparm) +{ + + ReadInfo *sccb = (void *)_sccb; + + memset((char *)_sccb, 0, sizeof(ReadInfo)); + sccb->h.length = sizeof(ReadInfo); + if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) { + ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8); + } +} diff --git a/pc-bios/s390-ccw/sclp.h b/pc-bios/s390-ccw/sclp.h index 3cbfb78..0dd987f 100644 --- a/pc-bios/s390-ccw/sclp.h +++ b/pc-bios/s390-ccw/sclp.h @@ -55,6 +55,8 @@ typedef struct ReadInfo { SCCBHeader h; uint16_t rnmax; uint8_t rnsize; + uint8_t reserved[13]; + uint8_t loadparm[8]; } __attribute__((packed)) ReadInfo; typedef struct SCCB { diff --git a/pc-bios/sgabios.bin b/pc-bios/sgabios.bin Binary files differindex c3da4c3..6308f2e 100644 --- a/pc-bios/sgabios.bin +++ b/pc-bios/sgabios.bin diff --git a/qapi-schema.json b/qapi-schema.json index 01b087f..5bb8cb7 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -4877,6 +4877,8 @@ # @nodelay: set TCP_NODELAY socket option (default: false) # @telnet: enable telnet protocol on server # sockets (default: false) +# @tn3270: enable tn3270 protocol on server +# sockets (default: false) (Since: 2.10) # @reconnect: For a client socket, if a socket is disconnected, # then attempt a reconnect after the given number of seconds. # Setting this to zero disables this function. (default: 0) @@ -4890,6 +4892,7 @@ '*wait' : 'bool', '*nodelay' : 'bool', '*telnet' : 'bool', + '*tn3270' : 'bool', '*reconnect' : 'int' }, 'base': 'ChardevCommon' } diff --git a/qemu-options.hx b/qemu-options.hx index f68829f..70c0ded 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -31,7 +31,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "-machine [type=]name[,prop[=value][,...]]\n" " selects emulated machine ('-machine help' for list)\n" " property accel=accel1[:accel2[:...]] selects accelerator\n" - " supported accelerators are kvm, xen, tcg (default: tcg)\n" + " supported accelerators are kvm, xen, hax or tcg (default: tcg)\n" " kernel_irqchip=on|off|split controls accelerated irqchip support (default=off)\n" " vmport=on|off|auto controls emulation of vmport (default: auto)\n" " kvm_shadow_mem=size of KVM shadow MMU in bytes\n" @@ -52,9 +52,9 @@ available machines. Supported machine properties are: @table @option @item accel=@var{accels1}[:@var{accels2}[:...]] This is used to enable an accelerator. Depending on the target architecture, -kvm, xen, or tcg can be available. By default, tcg is used. If there is more -than one accelerator specified, the next one is used if the previous one fails -to initialize. +kvm, xen, hax or tcg can be available. By default, tcg is used. If there is +more than one accelerator specified, the next one is used if the previous one +fails to initialize. @item kernel_irqchip=on|off Controls in-kernel irqchip support for the chosen accelerator when available. @item gfx_passthru=on|off @@ -97,15 +97,15 @@ ETEXI DEF("accel", HAS_ARG, QEMU_OPTION_accel, "-accel [accel=]accelerator[,thread=single|multi]\n" - " select accelerator ('-accel help for list')\n" - " thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL) + " select accelerator (kvm, xen, hax or tcg; use 'help' for a list)\n" + " thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL) STEXI @item -accel @var{name}[,prop=@var{value}[,...]] @findex -accel This is used to enable an accelerator. Depending on the target architecture, -kvm, xen, or tcg can be available. By default, tcg is used. If there is more -than one accelerator specified, the next one is used if the previous one fails -to initialize. +kvm, xen, hax or tcg can be available. By default, tcg is used. If there is +more than one accelerator specified, the next one is used if the previous one +fails to initialize. @table @option @item thread=single|multi Controls number of TCG threads. When the TCG is multi-threaded there will be one diff --git a/qom/container.c b/qom/container.c index c9eb49b..f6ccaf7 100644 --- a/qom/container.c +++ b/qom/container.c @@ -40,6 +40,7 @@ Object *container_get(Object *root, const char *path) if (!child) { child = object_new("container"); object_property_add_child(obj, parts[i], child, NULL); + object_unref(child); } } diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index 65e2d37..8cced46 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -64,7 +64,7 @@ void replay_vmstate_init(void) { if (replay_snapshot) { if (replay_mode == REPLAY_MODE_RECORD) { - if (save_vmstate(cur_mon, replay_snapshot) != 0) { + if (save_vmstate(replay_snapshot) != 0) { error_report("Could not create snapshot for icount record"); exit(1); } diff --git a/roms/sgabios b/roms/sgabios -Subproject 23d474943dcd55d0550a3d20b3d30e9040a4f15 +Subproject cbaee52287e5f32373181cff50a00b6c4ac9015 diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index f084542..73cee81 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2571,6 +2571,27 @@ sub process { if ($line =~ /\bbzero\(/) { ERROR("use memset() instead of bzero()\n" . $herecurr); } + my $non_exit_glib_asserts = qr{g_assert_cmpstr| + g_assert_cmpint| + g_assert_cmpuint| + g_assert_cmphex| + g_assert_cmpfloat| + g_assert_true| + g_assert_false| + g_assert_nonnull| + g_assert_null| + g_assert_no_error| + g_assert_error| + g_test_assert_expected_messages| + g_test_trap_assert_passed| + g_test_trap_assert_stdout| + g_test_trap_assert_stdout_unmatched| + g_test_trap_assert_stderr| + g_test_trap_assert_stderr_unmatched}x; + if ($realfile !~ /^tests\// && + $line =~ /\b(?:$non_exit_glib_asserts)\(/) { + ERROR("Use g_assert or g_assert_not_reached\n". $herecurr); + } } # If we have no input at all, then there is nothing to report on diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 8261bcb..96e66a8 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -21,6 +21,7 @@ my $lk_path = "./"; my $email = 1; my $email_usename = 1; my $email_maintainer = 1; +my $email_reviewer = 1; my $email_list = 1; my $email_subscriber_list = 0; my $email_git = 0; @@ -180,6 +181,7 @@ if (!GetOptions( 'remove-duplicates!' => \$email_remove_duplicates, 'mailmap!' => \$email_use_mailmap, 'm!' => \$email_maintainer, + 'r!' => \$email_reviewer, 'n!' => \$email_usename, 'l!' => \$email_list, 's!' => \$email_subscriber_list, @@ -238,7 +240,8 @@ if ($sections) { } if ($email && - ($email_maintainer + $email_list + $email_subscriber_list + + ($email_maintainer + $email_reviewer + + $email_list + $email_subscriber_list + $email_git + $email_git_blame) == 0) { die "$P: Please select at least 1 email option\n"; } @@ -718,6 +721,7 @@ MAINTAINER field selection options: --hg-since => hg history to use (default: $email_hg_since) --interactive => display a menu (mostly useful if used with the --git option) --m => include maintainer(s) if any + --r => include reviewer(s) if any --n => include name 'Full Name <addr\@domain.tld>' --l => include list(s) if any --s => include subscriber only list(s) if any @@ -744,7 +748,7 @@ Other options: --help => show this help information Default options: - [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0 + [--email --nogit --git-fallback --m --r --n --l --multiline --pattern-depth=0 --remove-duplicates --rolestats] Notes: @@ -892,20 +896,29 @@ sub find_ending_index { return $index; } -sub get_maintainer_role { +sub get_subsystem_name { my ($index) = @_; - my $i; my $start = find_starting_index($index); - my $end = find_ending_index($index); - my $role = "unknown"; my $subsystem = $typevalue[$start]; if (length($subsystem) > 20) { $subsystem = substr($subsystem, 0, 17); $subsystem =~ s/\s*$//; $subsystem = $subsystem . "..."; } + return $subsystem; +} + +sub get_maintainer_role { + my ($index) = @_; + + my $i; + my $start = find_starting_index($index); + my $end = find_ending_index($index); + + my $role = "unknown"; + my $subsystem = get_subsystem_name($index); for ($i = $start + 1; $i < $end; $i++) { my $tv = $typevalue[$i]; @@ -939,16 +952,7 @@ sub get_maintainer_role { sub get_list_role { my ($index) = @_; - my $i; - my $start = find_starting_index($index); - my $end = find_ending_index($index); - - my $subsystem = $typevalue[$start]; - if (length($subsystem) > 20) { - $subsystem = substr($subsystem, 0, 17); - $subsystem =~ s/\s*$//; - $subsystem = $subsystem . "..."; - } + my $subsystem = get_subsystem_name($index); if ($subsystem eq "THE REST") { $subsystem = ""; @@ -1022,6 +1026,23 @@ sub add_categories { my $role = get_maintainer_role($i); push_email_addresses($pvalue, $role); } + } elsif ($ptype eq "R") { + my ($name, $address) = parse_email($pvalue); + if ($name eq "") { + if ($i > 0) { + my $tv = $typevalue[$i - 1]; + if ($tv =~ m/^(.):\s*(.*)/) { + if ($1 eq "P") { + $name = $2; + $pvalue = format_email($name, $address, $email_usename); + } + } + } + } + if ($email_reviewer) { + my $subsystem = get_subsystem_name($i); + push_email_addresses($pvalue, "reviewer:$subsystem"); + } } elsif ($ptype eq "T") { push(@scm, $pvalue); } elsif ($ptype eq "W") { diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index 365446f..1ffbc1d 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -191,6 +191,10 @@ class Event(object): self.event_trans = event_trans self.event_exec = event_exec + if len(args) > 10: + raise ValueError("Event '%s' has more than maximum permitted " + "argument count" % name) + if orig is None: self.original = weakref.ref(self) else: diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 13c0985..7e87031 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2577,6 +2577,15 @@ out: return ret; } +static gchar *x86_gdb_arch_name(CPUState *cs) +{ +#ifdef TARGET_X86_64 + return g_strdup("i386:x86-64"); +#else + return g_strdup("i386"); +#endif +} + X86CPU *cpu_x86_init(const char *cpu_model) { return X86_CPU(cpu_generic_init(TYPE_X86_CPU, cpu_model)); @@ -4056,10 +4065,14 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote; cc->vmsd = &vmstate_x86_cpu; #endif - /* CPU_NB_REGS * 2 = general regs + xmm regs - * 25 = eip, eflags, 6 seg regs, st[0-7], fctrl,...,fop, mxcsr. - */ - cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25; + cc->gdb_arch_name = x86_gdb_arch_name; +#ifdef TARGET_X86_64 + cc->gdb_core_xml_file = "i386-64bit-core.xml"; + cc->gdb_num_core_regs = 40; +#else + cc->gdb_core_xml_file = "i386-32bit-core.xml"; + cc->gdb_num_core_regs = 32; +#endif #ifndef CONFIG_USER_ONLY cc->debug_excp_handler = breakpoint_handler; #endif diff --git a/target/i386/hax-mem.c b/target/i386/hax-mem.c index 2884040..af09034 100644 --- a/target/i386/hax-mem.c +++ b/target/i386/hax-mem.c @@ -106,10 +106,10 @@ static void hax_update_mapping(uint64_t start_pa, uint32_t size, uint64_t host_va, uint8_t flags) { uint64_t end_pa = start_pa + size; - uint32_t chunk_sz; HAXMapping *entry, *next; QTAILQ_FOREACH_SAFE(entry, &mappings, entry, next) { + uint32_t chunk_sz; if (start_pa >= entry->start_pa + entry->size) { continue; } @@ -121,7 +121,16 @@ static void hax_update_mapping(uint64_t start_pa, uint32_t size, start_pa += chunk_sz; host_va += chunk_sz; size -= chunk_sz; + } else if (start_pa > entry->start_pa) { + /* split the existing chunk at start_pa */ + chunk_sz = start_pa - entry->start_pa; + hax_insert_mapping_before(entry, entry->start_pa, chunk_sz, + entry->host_va, entry->flags); + entry->start_pa += chunk_sz; + entry->host_va += chunk_sz; + entry->size -= chunk_sz; } + /* now start_pa == entry->start_pa */ chunk_sz = MIN(size, entry->size); if (chunk_sz) { bool nop = hax_mapping_is_opposite(entry, host_va, flags); @@ -165,8 +174,14 @@ static void hax_process_section(MemoryRegionSection *section, uint8_t flags) unsigned int delta; uint64_t host_va; - /* We only care about RAM pages */ + /* We only care about RAM and ROM regions */ if (!memory_region_is_ram(mr)) { + if (memory_region_is_romd(mr)) { + /* HAXM kernel module does not support ROMD yet */ + fprintf(stderr, "%s: Warning: Ignoring ROMD region 0x%016" PRIx64 + "->0x%016" PRIx64 "\n", __func__, start_pa, + start_pa + size); + } return; } diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 7fd2b9a..1d6330c 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -51,8 +51,8 @@ static void openrisc_cpu_reset(CPUState *s) cpu->env.lock_addr = -1; s->exception_index = -1; - cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP; - cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S; + cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP | + UPR_PMP; cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2)); cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2)); @@ -65,12 +65,6 @@ static void openrisc_cpu_reset(CPUState *s) #endif } -static inline void set_feature(OpenRISCCPU *cpu, int feature) -{ - cpu->feature |= feature; - cpu->env.cpucfgr = cpu->feature; -} - static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -132,15 +126,15 @@ static void or1200_initfn(Object *obj) { OpenRISCCPU *cpu = OPENRISC_CPU(obj); - set_feature(cpu, OPENRISC_FEATURE_OB32S); - set_feature(cpu, OPENRISC_FEATURE_OF32S); + cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_OF32S | + CPUCFGR_EVBARP; } static void openrisc_any_initfn(Object *obj) { OpenRISCCPU *cpu = OPENRISC_CPU(obj); - set_feature(cpu, OPENRISC_FEATURE_OB32S); + cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_EVBARP; } typedef struct OpenRISCCPUInfo { diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 418a0e6..2721432 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -111,6 +111,11 @@ enum { CPUCFGR_OF32S = (1 << 7), CPUCFGR_OF64S = (1 << 8), CPUCFGR_OV64S = (1 << 9), + /* CPUCFGR_ND = (1 << 10), */ + /* CPUCFGR_AVRP = (1 << 11), */ + CPUCFGR_EVBARP = (1 << 12), + /* CPUCFGR_ISRP = (1 << 13), */ + /* CPUCFGR_AECSRP = (1 << 14), */ }; /* DMMU configure register */ @@ -135,6 +140,15 @@ enum { IMMUCFGR_HTR = (1 << 11), }; +/* Power management register */ +enum { + PMR_SDF = (15 << 0), + PMR_DME = (1 << 4), + PMR_SME = (1 << 5), + PMR_DCGE = (1 << 6), + PMR_SUME = (1 << 7), +}; + /* Float point control status register */ enum { FPCSR_FPEE = 1, @@ -191,17 +205,6 @@ enum { SR_SCE = (1 << 17), }; -/* OpenRISC Hardware Capabilities */ -enum { - OPENRISC_FEATURE_NSGF = (15 << 0), - OPENRISC_FEATURE_CGF = (1 << 4), - OPENRISC_FEATURE_OB32S = (1 << 5), - OPENRISC_FEATURE_OB64S = (1 << 6), - OPENRISC_FEATURE_OF32S = (1 << 7), - OPENRISC_FEATURE_OF64S = (1 << 8), - OPENRISC_FEATURE_OV64S = (1 << 9), -}; - /* Tick Timer Mode Register */ enum { TTMR_TP = (0xfffffff), @@ -269,7 +272,8 @@ typedef struct CPUOpenRISCTLBContext { #endif typedef struct CPUOpenRISCState { - target_ulong gpr[32]; /* General registers */ + target_ulong shadow_gpr[16][32]; /* Shadow registers */ + target_ulong pc; /* Program counter */ target_ulong ppc; /* Prev PC */ target_ulong jmp_pc; /* Jump PC */ @@ -285,10 +289,11 @@ typedef struct CPUOpenRISCState { uint32_t sr; /* Supervisor register, without SR_{F,CY,OV} */ uint32_t vr; /* Version register */ uint32_t upr; /* Unit presence register */ - uint32_t cpucfgr; /* CPU configure register */ uint32_t dmmucfgr; /* DMMU configure register */ uint32_t immucfgr; /* IMMU configure register */ uint32_t esr; /* Exception supervisor register */ + uint32_t evbar; /* Exception vector base address register */ + uint32_t pmr; /* Power Management Register */ uint32_t fpcsr; /* Float register */ float_status fp_status; @@ -303,6 +308,8 @@ typedef struct CPUOpenRISCState { CPU_COMMON /* Fields from here on are preserved across CPU reset. */ + uint32_t cpucfgr; /* CPU configure register */ + #ifndef CONFIG_USER_ONLY CPUOpenRISCTLBContext * tlb; @@ -329,7 +336,6 @@ typedef struct OpenRISCCPU { CPUOpenRISCState env; - uint32_t feature; /* CPU Capabilities */ } OpenRISCCPU; static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env) @@ -392,6 +398,16 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu, #define TB_FLAGS_R0_0 2 #define TB_FLAGS_OVE SR_OVE +static inline uint32_t cpu_get_gpr(const CPUOpenRISCState *env, int i) +{ + return env->shadow_gpr[0][i]; +} + +static inline void cpu_set_gpr(CPUOpenRISCState *env, int i, uint32_t val) +{ + env->shadow_gpr[0][i] = val; +} + static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) @@ -399,7 +415,7 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, *pc = env->pc; *cs_base = 0; *flags = (env->dflag - | (env->gpr[0] == 0 ? TB_FLAGS_R0_0 : 0) + | (cpu_get_gpr(env, 0) == 0 ? TB_FLAGS_R0_0 : 0) | (env->sr & SR_OVE)); } diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c index b18c7e9..f9af650 100644 --- a/target/openrisc/gdbstub.c +++ b/target/openrisc/gdbstub.c @@ -28,7 +28,7 @@ int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) CPUOpenRISCState *env = &cpu->env; if (n < 32) { - return gdb_get_reg32(mem_buf, env->gpr[n]); + return gdb_get_reg32(mem_buf, cpu_get_gpr(env, n)); } else { switch (n) { case 32: /* PPC */ @@ -61,7 +61,7 @@ int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) tmp = ldl_p(mem_buf); if (n < 32) { - env->gpr[n] = tmp; + cpu_set_gpr(env, n, tmp); } else { switch (n) { case 32: /* PPC */ diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index a2eec6f..3959671 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -60,12 +60,21 @@ void openrisc_cpu_do_interrupt(CPUState *cs) env->sr |= SR_SM; env->sr &= ~SR_IEE; env->sr &= ~SR_TEE; + env->pmr &= ~PMR_DME; + env->pmr &= ~PMR_SME; env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu; env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu; env->lock_addr = -1; if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) { - env->pc = (cs->exception_index << 8); + hwaddr vect_pc = cs->exception_index << 8; + if (env->cpucfgr & CPUCFGR_EVBARP) { + vect_pc |= env->evbar; + } + if (env->sr & SR_EPH) { + vect_pc |= 0xf0000000; + } + env->pc = vect_pc; } else { cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); } diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c index 686eaa3..a20cce7 100644 --- a/target/openrisc/machine.c +++ b/target/openrisc/machine.c @@ -24,6 +24,63 @@ #include "hw/boards.h" #include "migration/cpu.h" +static int env_post_load(void *opaque, int version_id) +{ + CPUOpenRISCState *env = opaque; + + /* Restore MMU handlers */ + if (env->sr & SR_DME) { + env->tlb->cpu_openrisc_map_address_data = + &cpu_openrisc_get_phys_data; + } else { + env->tlb->cpu_openrisc_map_address_data = + &cpu_openrisc_get_phys_nommu; + } + + if (env->sr & SR_IME) { + env->tlb->cpu_openrisc_map_address_code = + &cpu_openrisc_get_phys_code; + } else { + env->tlb->cpu_openrisc_map_address_code = + &cpu_openrisc_get_phys_nommu; + } + + + return 0; +} + +static const VMStateDescription vmstate_tlb_entry = { + .name = "tlb_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINTTL(mr, OpenRISCTLBEntry), + VMSTATE_UINTTL(tr, OpenRISCTLBEntry), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_cpu_tlb = { + .name = "cpu_tlb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_2DARRAY(itlb, CPUOpenRISCTLBContext, + ITLB_WAYS, ITLB_SIZE, 0, + vmstate_tlb_entry, OpenRISCTLBEntry), + VMSTATE_STRUCT_2DARRAY(dtlb, CPUOpenRISCTLBContext, + DTLB_WAYS, DTLB_SIZE, 0, + vmstate_tlb_entry, OpenRISCTLBEntry), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_CPU_TLB(_f, _s) \ + VMSTATE_STRUCT_POINTER(_f, _s, vmstate_cpu_tlb, CPUOpenRISCTLBContext) + + static int get_sr(QEMUFile *f, void *opaque, size_t size, VMStateField *field) { CPUOpenRISCState *env = opaque; @@ -47,10 +104,11 @@ static const VMStateInfo vmstate_sr = { static const VMStateDescription vmstate_env = { .name = "env", - .version_id = 4, - .minimum_version_id = 4, + .version_id = 6, + .minimum_version_id = 6, + .post_load = env_post_load, .fields = (VMStateField[]) { - VMSTATE_UINTTL_ARRAY(gpr, CPUOpenRISCState, 32), + VMSTATE_UINTTL_2DARRAY(shadow_gpr, CPUOpenRISCState, 16, 32), VMSTATE_UINTTL(pc, CPUOpenRISCState), VMSTATE_UINTTL(ppc, CPUOpenRISCState), VMSTATE_UINTTL(jmp_pc, CPUOpenRISCState), @@ -79,9 +137,21 @@ static const VMStateDescription vmstate_env = { VMSTATE_UINT32(cpucfgr, CPUOpenRISCState), VMSTATE_UINT32(dmmucfgr, CPUOpenRISCState), VMSTATE_UINT32(immucfgr, CPUOpenRISCState), + VMSTATE_UINT32(evbar, CPUOpenRISCState), + VMSTATE_UINT32(pmr, CPUOpenRISCState), VMSTATE_UINT32(esr, CPUOpenRISCState), VMSTATE_UINT32(fpcsr, CPUOpenRISCState), VMSTATE_UINT64(mac, CPUOpenRISCState), + + VMSTATE_CPU_TLB(tlb, CPUOpenRISCState), + + VMSTATE_TIMER_PTR(timer, CPUOpenRISCState), + VMSTATE_UINT32(ttmr, CPUOpenRISCState), + VMSTATE_UINT32(ttcr, CPUOpenRISCState), + + VMSTATE_UINT32(picmr, CPUOpenRISCState), + VMSTATE_UINT32(picsr, CPUOpenRISCState), + VMSTATE_END_OF_LIST() } }; diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index 56b11d3..ce2a29d 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -124,7 +124,7 @@ static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu, { int ret = TLBRET_MATCH; - if (rw == 2) { /* ITLB */ + if (rw == MMU_INST_FETCH) { /* ITLB */ *physical = 0; ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical, prot, address, rw); @@ -221,12 +221,28 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) OpenRISCCPU *cpu = OPENRISC_CPU(cs); hwaddr phys_addr; int prot; + int miss; - if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) { - return -1; + /* Check memory for any kind of address, since during debug the + gdb can ask for anything, check data tlb for address */ + miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0); + + /* Check instruction tlb */ + if (miss) { + miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, + MMU_INST_FETCH); + } + + /* Last, fall back to a plain address */ + if (miss) { + miss = cpu_openrisc_get_phys_nommu(cpu, &phys_addr, &prot, addr, 0); } - return phys_addr; + if (miss) { + return -1; + } else { + return phys_addr; + } } void cpu_openrisc_mmu_init(OpenRISCCPU *cpu) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 60c3193..abdef5d 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "exception.h" #define TO_SPR(group, number) (((group) << 11) + (number)) @@ -39,6 +40,10 @@ void HELPER(mtspr)(CPUOpenRISCState *env, env->vr = rb; break; + case TO_SPR(0, 11): /* EVBAR */ + env->evbar = rb; + break; + case TO_SPR(0, 16): /* NPC */ cpu_restore_state(cs, GETPC()); /* ??? Mirror or1ksim in not trashing delayed branch state @@ -88,6 +93,11 @@ void HELPER(mtspr)(CPUOpenRISCState *env, case TO_SPR(0, 64): /* ESR */ env->esr = rb; break; + + case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */ + idx = (spr - 1024); + env->shadow_gpr[idx / 32][idx % 32] = rb; + case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */ idx = spr - TO_SPR(1, 512); if (!(rb & 1)) { @@ -132,6 +142,15 @@ void HELPER(mtspr)(CPUOpenRISCState *env, case TO_SPR(5, 2): /* MACHI */ env->mac = deposit64(env->mac, 32, 32, rb); break; + case TO_SPR(8, 0): /* PMR */ + env->pmr = rb; + if (env->pmr & PMR_DME || env->pmr & PMR_SME) { + cpu_restore_state(cs, GETPC()); + env->pc += 4; + cs->halted = 1; + raise_exception(cpu, EXCP_HALTED); + } + break; case TO_SPR(9, 0): /* PICMR */ env->picmr |= rb; break; @@ -206,6 +225,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(0, 4): /* IMMUCFGR */ return env->immucfgr; + case TO_SPR(0, 11): /* EVBAR */ + return env->evbar; + case TO_SPR(0, 16): /* NPC (equals PC) */ cpu_restore_state(cs, GETPC()); return env->pc; @@ -226,6 +248,16 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(0, 64): /* ESR */ return env->esr; + case TO_SPR(0, 128): /* COREID */ + return 0; + + case TO_SPR(0, 129): /* NUMCORES */ + return 1; + + case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */ + idx = (spr - 1024); + return env->shadow_gpr[idx / 32][idx % 32]; + case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */ idx = spr - TO_SPR(1, 512); return env->tlb->dtlb[0][idx].mr; @@ -265,6 +297,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, return env->mac >> 32; break; + case TO_SPR(8, 0): /* PMR */ + return env->pmr; + case TO_SPR(9, 0): /* PICMR */ return env->picmr; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 7c4cbf2..e49518e 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -107,7 +107,8 @@ void openrisc_translate_init(void) "mac"); for (i = 0; i < 32; i++) { cpu_R[i] = tcg_global_mem_new(cpu_env, - offsetof(CPUOpenRISCState, gpr[i]), + offsetof(CPUOpenRISCState, + shadow_gpr[0][i]), regnames[i]); } cpu_R0 = cpu_R[0]; @@ -1662,7 +1663,7 @@ void openrisc_cpu_dump_state(CPUState *cs, FILE *f, cpu_fprintf(f, "PC=%08x\n", env->pc); for (i = 0; i < 32; ++i) { - cpu_fprintf(f, "R%02d=%08x%c", i, env->gpr[i], + cpu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i), (i % 4) == 3 ? '\n' : ' '); } } diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h index 348e4d7..f8d8723 100644 --- a/tests/acpi-utils.h +++ b/tests/acpi-utils.h @@ -87,6 +87,16 @@ typedef struct { g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \ } while (0) +#define ACPI_READ_GENERIC_ADDRESS(field, addr) \ + do { \ + ACPI_READ_FIELD((field).space_id, addr); \ + ACPI_READ_FIELD((field).bit_width, addr); \ + ACPI_READ_FIELD((field).bit_offset, addr); \ + ACPI_READ_FIELD((field).access_width, addr); \ + ACPI_READ_FIELD((field).address, addr); \ + } while (0); + + uint8_t acpi_calc_checksum(const uint8_t *data, int len); uint32_t acpi_find_rsdp_address(void); void acpi_parse_rsdp_table(uint32_t addr, AcpiRsdpDescriptor *rsdp_table); diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 88dbf97..9c96a67 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -29,7 +29,7 @@ typedef struct { uint32_t rsdp_addr; AcpiRsdpDescriptor rsdp_table; AcpiRsdtDescriptorRev1 rsdt_table; - AcpiFadtDescriptorRev1 fadt_table; + AcpiFadtDescriptorRev3 fadt_table; AcpiFacsDescriptorRev1 facs_table; uint32_t *rsdt_tables_addr; int rsdt_tables_nr; @@ -126,7 +126,7 @@ static void test_acpi_rsdt_table(test_data *data) static void test_acpi_fadt_table(test_data *data) { - AcpiFadtDescriptorRev1 *fadt_table = &data->fadt_table; + AcpiFadtDescriptorRev3 *fadt_table = &data->fadt_table; uint32_t addr; /* FADT table comes first */ @@ -168,10 +168,23 @@ static void test_acpi_fadt_table(test_data *data) ACPI_READ_FIELD(fadt_table->day_alrm, addr); ACPI_READ_FIELD(fadt_table->mon_alrm, addr); ACPI_READ_FIELD(fadt_table->century, addr); - ACPI_READ_FIELD(fadt_table->reserved4, addr); - ACPI_READ_FIELD(fadt_table->reserved4a, addr); - ACPI_READ_FIELD(fadt_table->reserved4b, addr); + ACPI_READ_FIELD(fadt_table->boot_flags, addr); + ACPI_READ_FIELD(fadt_table->reserved, addr); ACPI_READ_FIELD(fadt_table->flags, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->reset_register, addr); + ACPI_READ_FIELD(fadt_table->reset_value, addr); + ACPI_READ_FIELD(fadt_table->arm_boot_flags, addr); + ACPI_READ_FIELD(fadt_table->minor_revision, addr); + ACPI_READ_FIELD(fadt_table->Xfacs, addr); + ACPI_READ_FIELD(fadt_table->Xdsdt, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1a_event_block, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1b_event_block, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1a_control_block, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1b_control_block, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm2_control_block, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm_timer_block, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xgpe0_block, addr); + ACPI_READ_GENERIC_ADDRESS(fadt_table->xgpe1_block, addr); ACPI_ASSERT_CMP(fadt_table->signature, "FACP"); g_assert(!acpi_calc_checksum((uint8_t *)fadt_table, fadt_table->length)); diff --git a/tests/test-char.c b/tests/test-char.c index da69f11..773a1c3 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -1,18 +1,35 @@ #include "qemu/osdep.h" +#include <glib/gstdio.h> #include "qemu-common.h" #include "qemu/config-file.h" +#include "qemu/sockets.h" #include "sysemu/char.h" #include "sysemu/sysemu.h" #include "qapi/error.h" +#include "qom/qom-qobject.h" #include "qmp-commands.h" +static bool quit; + typedef struct FeHandler { int read_count; int last_event; char read_buf[128]; } FeHandler; +static void main_loop(void) +{ + bool nonblocking; + int last_io = 0; + + quit = false; + do { + nonblocking = last_io > 0; + last_io = main_loop_wait(nonblocking); + } while (!quit); +} + static int fe_can_read(void *opaque) { FeHandler *h = opaque; @@ -28,6 +45,7 @@ static void fe_read(void *opaque, const uint8_t *buf, int size) memcpy(h->read_buf + h->read_count, buf, size); h->read_count += size; + quit = true; } static void fe_event(void *opaque, int event) @@ -35,9 +53,36 @@ static void fe_event(void *opaque, int event) FeHandler *h = opaque; h->last_event = event; + quit = true; } #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS +#ifdef _WIN32 +static void char_console_test_subprocess(void) +{ + QemuOpts *opts; + Chardev *chr; + + opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label", + 1, &error_abort); + qemu_opt_set(opts, "backend", "console", &error_abort); + + chr = qemu_chr_new_from_opts(opts, NULL); + g_assert_nonnull(chr); + + qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7); + + qemu_opts_del(opts); + object_unparent(OBJECT(chr)); +} + +static void char_console_test(void) +{ + g_test_trap_subprocess("/char/console/subprocess", 0, 0); + g_test_trap_assert_passed(); + g_test_trap_assert_stdout("CONSOLE"); +} +#endif static void char_stdio_test_subprocess(void) { Chardev *chr; @@ -53,7 +98,7 @@ static void char_stdio_test_subprocess(void) g_assert_cmpint(ret, ==, 4); qemu_chr_fe_deinit(&be); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); } static void char_stdio_test(void) @@ -64,7 +109,6 @@ static void char_stdio_test(void) } #endif - static void char_ringbuf_test(void) { QemuOpts *opts; @@ -103,7 +147,17 @@ static void char_ringbuf_test(void) g_free(data); qemu_chr_fe_deinit(&be); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); + + /* check alias */ + opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label", + 1, &error_abort); + qemu_opt_set(opts, "backend", "memory", &error_abort); + qemu_opt_set(opts, "size", "2", &error_abort); + chr = qemu_chr_new_from_opts(opts, NULL); + g_assert_nonnull(chr); + object_unparent(OBJECT(chr)); + qemu_opts_del(opts); } static void char_mux_test(void) @@ -179,7 +233,296 @@ static void char_mux_test(void) qemu_chr_fe_deinit(&chr_be1); qemu_chr_fe_deinit(&chr_be2); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); +} + +typedef struct SocketIdleData { + GMainLoop *loop; + Chardev *chr; + bool conn_expected; + CharBackend *be; + CharBackend *client_be; +} SocketIdleData; + +static gboolean char_socket_test_idle(gpointer user_data) +{ + SocketIdleData *data = user_data; + + if (object_property_get_bool(OBJECT(data->chr), "connected", NULL) + == data->conn_expected) { + quit = true; + return FALSE; + } + + return TRUE; +} + +static void socket_read(void *opaque, const uint8_t *buf, int size) +{ + SocketIdleData *data = opaque; + + g_assert_cmpint(size, ==, 1); + g_assert_cmpint(*buf, ==, 'Z'); + + size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5); + g_assert_cmpint(size, ==, 5); +} + +static int socket_can_read(void *opaque) +{ + return 10; +} + +static void socket_read_hello(void *opaque, const uint8_t *buf, int size) +{ + g_assert_cmpint(size, ==, 5); + g_assert(strncmp((char *)buf, "hello", 5) == 0); + + quit = true; +} + +static int socket_can_read_hello(void *opaque) +{ + return 10; +} + +static void char_socket_test(void) +{ + Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait"); + Chardev *chr_client; + QObject *addr; + QDict *qdict, *data; + const char *port; + SocketIdleData d = { .chr = chr }; + CharBackend be; + CharBackend client_be; + char *tmp; + + d.be = &be; + d.client_be = &be; + + g_assert_nonnull(chr); + g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); + + addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); + qdict = qobject_to_qdict(addr); + data = qdict_get_qdict(qdict, "data"); + port = qdict_get_str(data, "port"); + tmp = g_strdup_printf("tcp:127.0.0.1:%s", port); + QDECREF(qdict); + + qemu_chr_fe_init(&be, chr, &error_abort); + qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read, + NULL, &d, NULL, true); + + chr_client = qemu_chr_new("client", tmp); + qemu_chr_fe_init(&client_be, chr_client, &error_abort); + qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello, + socket_read_hello, + NULL, &d, NULL, true); + g_free(tmp); + + d.conn_expected = true; + guint id = g_idle_add(char_socket_test_idle, &d); + g_source_set_name_by_id(id, "test-idle"); + g_assert_cmpint(id, >, 0); + main_loop(); + + g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); + g_assert(object_property_get_bool(OBJECT(chr_client), + "connected", &error_abort)); + + qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1); + main_loop(); + + object_unparent(OBJECT(chr_client)); + + d.conn_expected = false; + g_idle_add(char_socket_test_idle, &d); + main_loop(); + + object_unparent(OBJECT(chr)); +} + +#ifndef _WIN32 +static void char_pipe_test(void) +{ + gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); + gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL); + Chardev *chr; + CharBackend be; + int ret, fd; + char buf[10]; + FeHandler fe = { 0, }; + + in = g_strdup_printf("%s.in", pipe); + if (mkfifo(in, 0600) < 0) { + abort(); + } + out = g_strdup_printf("%s.out", pipe); + if (mkfifo(out, 0600) < 0) { + abort(); + } + + tmp = g_strdup_printf("pipe:%s", pipe); + chr = qemu_chr_new("pipe", tmp); + g_assert_nonnull(chr); + g_free(tmp); + + qemu_chr_fe_init(&be, chr, &error_abort); + + ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9); + g_assert_cmpint(ret, ==, 9); + + fd = open(out, O_RDWR); + ret = read(fd, buf, sizeof(buf)); + g_assert_cmpint(ret, ==, 9); + g_assert_cmpstr(buf, ==, "pipe-out"); + close(fd); + + fd = open(in, O_WRONLY); + ret = write(fd, "pipe-in", 8); + g_assert_cmpint(ret, ==, 8); + close(fd); + + qemu_chr_fe_set_handlers(&be, + fe_can_read, + fe_read, + fe_event, + &fe, + NULL, true); + + main_loop(); + + g_assert_cmpint(fe.read_count, ==, 8); + g_assert_cmpstr(fe.read_buf, ==, "pipe-in"); + + qemu_chr_fe_deinit(&be); + object_unparent(OBJECT(chr)); + + g_assert(g_unlink(in) == 0); + g_assert(g_unlink(out) == 0); + g_assert(g_rmdir(tmp_path) == 0); + g_free(in); + g_free(out); + g_free(tmp_path); + g_free(pipe); +} +#endif + +static void char_udp_test(void) +{ + struct sockaddr_in addr = { 0, }, other; + SocketIdleData d = { 0, }; + Chardev *chr; + CharBackend be; + socklen_t alen = sizeof(addr); + int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0); + char buf[10]; + char *tmp; + + g_assert_cmpint(sock, >, 0); + addr.sin_family = AF_INET ; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = 0; + ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + g_assert_cmpint(ret, ==, 0); + ret = getsockname(sock, (struct sockaddr *)&addr, &alen); + g_assert_cmpint(ret, ==, 0); + + tmp = g_strdup_printf("udp:127.0.0.1:%d", + ntohs(addr.sin_port)); + chr = qemu_chr_new("client", tmp); + g_assert_nonnull(chr); + + d.chr = chr; + qemu_chr_fe_init(&be, chr, &error_abort); + qemu_chr_fe_set_handlers(&be, socket_can_read_hello, socket_read_hello, + NULL, &d, NULL, true); + ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5); + g_assert_cmpint(ret, ==, 5); + + alen = sizeof(addr); + ret = recvfrom(sock, buf, sizeof(buf), 0, + (struct sockaddr *)&other, &alen); + g_assert_cmpint(ret, ==, 5); + ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen); + g_assert_cmpint(ret, ==, 5); + + main_loop(); + + close(sock); + g_free(tmp); +} + +static void char_file_test(void) +{ + char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); + char *out = g_build_filename(tmp_path, "out", NULL); + char *contents = NULL; + ChardevFile file = { .out = out }; + ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, + .u.file.data = &file }; + Chardev *chr; + gsize length; + int ret; + + chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend, + &error_abort); + ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6); + g_assert_cmpint(ret, ==, 6); + object_unref(OBJECT(chr)); + + ret = g_file_get_contents(out, &contents, &length, NULL); + g_assert(ret == TRUE); + g_assert_cmpint(length, ==, 6); + g_assert(strncmp(contents, "hello!", 6) == 0); + g_free(contents); + +#ifndef _WIN32 + { + CharBackend be; + FeHandler fe = { 0, }; + char *fifo = g_build_filename(tmp_path, "fifo", NULL); + int fd; + + if (mkfifo(fifo, 0600) < 0) { + abort(); + } + + fd = open(fifo, O_RDWR); + ret = write(fd, "fifo-in", 8); + g_assert_cmpint(ret, ==, 8); + + file.in = fifo; + file.has_in = true; + chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend, + &error_abort); + + qemu_chr_fe_init(&be, chr, &error_abort); + qemu_chr_fe_set_handlers(&be, + fe_can_read, + fe_read, + fe_event, + &fe, NULL, true); + + main_loop(); + + close(fd); + + g_assert_cmpint(fe.read_count, ==, 8); + g_assert_cmpstr(fe.read_buf, ==, "fifo-in"); + qemu_chr_fe_deinit(&be); + object_unref(OBJECT(chr)); + g_unlink(fifo); + g_free(fifo); + } +#endif + + g_unlink(out); + g_rmdir(tmp_path); + g_free(tmp_path); + g_free(out); } static void char_null_test(void) @@ -222,7 +565,7 @@ static void char_null_test(void) g_assert_cmpint(ret, ==, 4); qemu_chr_fe_deinit(&be); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); } static void char_invalid_test(void) @@ -235,6 +578,9 @@ static void char_invalid_test(void) int main(int argc, char **argv) { + qemu_init_main_loop(&error_abort); + socket_init(); + g_test_init(&argc, &argv, NULL); module_call_init(MODULE_INIT_QOM); @@ -245,9 +591,19 @@ int main(int argc, char **argv) g_test_add_func("/char/ringbuf", char_ringbuf_test); g_test_add_func("/char/mux", char_mux_test); #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS +#ifdef _WIN32 + g_test_add_func("/char/console/subprocess", char_console_test_subprocess); + g_test_add_func("/char/console", char_console_test); +#endif g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess); g_test_add_func("/char/stdio", char_stdio_test); #endif +#ifndef _WIN32 + g_test_add_func("/char/pipe", char_pipe_test); +#endif + g_test_add_func("/char/file", char_file_test); + g_test_add_func("/char/socket", char_socket_test); + g_test_add_func("/char/udp", char_udp_test); return g_test_run(); } diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index a61896c..9095af2 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -491,7 +491,7 @@ static gboolean _test_server_free(TestServer *server) Chardev *chr = qemu_chr_fe_get_driver(&server->chr); qemu_chr_fe_deinit(&server->chr); - qemu_chr_delete(chr); + object_unparent(OBJECT(chr)); for (i = 0; i < server->fds_num; i++) { close(server->fds[i]); diff --git a/ui/console.c b/ui/console.c index 189eecf..ac66b3c 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2076,7 +2076,7 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds) s->t_attrib = s->t_attrib_default; } - qemu_chr_be_generic_open(chr); + qemu_chr_be_event(chr, CHR_EVENT_OPENED); } static void vc_chr_open(Chardev *chr, @@ -1868,7 +1868,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc, gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item, gtk_label_new(vc->label)); - qemu_chr_be_generic_open(vc->vte.chr); + qemu_chr_be_event(vc->vte.chr, CHR_EVENT_OPENED); return group; } @@ -41,6 +41,8 @@ static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue); static QEMUTimer *kbd_timer; static uint32_t kbd_default_delay_ms = 10; +static uint32_t queue_count; +static uint32_t queue_limit = 1024; QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, QemuInputHandler *handler) @@ -268,6 +270,7 @@ static void qemu_input_queue_process(void *opaque) break; } QTAILQ_REMOVE(queue, item, node); + queue_count--; g_free(item); } } @@ -282,6 +285,7 @@ static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue, item->delay_ms = delay_ms; item->timer = timer; QTAILQ_INSERT_TAIL(queue, item, node); + queue_count++; if (start_timer) { timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) @@ -298,6 +302,7 @@ static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue, item->src = src; item->evt = evt; QTAILQ_INSERT_TAIL(queue, item, node); + queue_count++; } static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue) @@ -306,6 +311,7 @@ static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue) item->type = QEMU_INPUT_QUEUE_SYNC; QTAILQ_INSERT_TAIL(queue, item, node); + queue_count++; } void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt) @@ -381,7 +387,7 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down) qemu_input_event_send(src, evt); qemu_input_event_sync(); qapi_free_InputEvent(evt); - } else { + } else if (queue_count < queue_limit) { qemu_input_queue_event(&kbd_queue, src, evt); qemu_input_queue_sync(&kbd_queue); } @@ -405,12 +411,18 @@ void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down) void qemu_input_event_send_key_delay(uint32_t delay_ms) { + if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { + return; + } + if (!kbd_timer) { kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process, &kbd_queue); } - qemu_input_queue_delay(&kbd_queue, kbd_timer, - delay_ms ? delay_ms : kbd_default_delay_ms); + if (queue_count < queue_limit) { + qemu_input_queue_delay(&kbd_queue, kbd_timer, + delay_ms ? delay_ms : kbd_default_delay_ms); + } } InputEvent *qemu_input_event_new_btn(InputButton btn, bool down) diff --git a/util/qemu-config.c b/util/qemu-config.c index 5527100..405dd1a 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -227,6 +227,12 @@ static QemuOptsList machine_opts = { .name = "dea-key-wrap", .type = QEMU_OPT_BOOL, .help = "enable/disable DEA key wrapping using the CPACF wrapping key", + },{ + .name = "loadparm", + .type = QEMU_OPT_STRING, + .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars" + " converted to upper case) to pass to machine" + " loader, boot manager, and guest kernel", }, { /* End of list */ } } diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index 73e3a0e..eacd99e 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -14,6 +14,7 @@ #include "qemu/thread.h" #include "qemu/atomic.h" #include "qemu/notify.h" +#include "trace.h" static bool name_threads; @@ -60,17 +61,30 @@ void qemu_mutex_lock(QemuMutex *mutex) err = pthread_mutex_lock(&mutex->lock); if (err) error_exit(err, __func__); + + trace_qemu_mutex_locked(mutex); } int qemu_mutex_trylock(QemuMutex *mutex) { - return pthread_mutex_trylock(&mutex->lock); + int err; + + err = pthread_mutex_trylock(&mutex->lock); + if (err == 0) { + trace_qemu_mutex_locked(mutex); + return 0; + } + if (err != EBUSY) { + error_exit(err, __func__); + } + return -EBUSY; } void qemu_mutex_unlock(QemuMutex *mutex) { int err; + trace_qemu_mutex_unlocked(mutex); err = pthread_mutex_unlock(&mutex->lock); if (err) error_exit(err, __func__); @@ -130,7 +144,9 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) { int err; + trace_qemu_mutex_unlocked(mutex); err = pthread_cond_wait(&cond->cond, &mutex->lock); + trace_qemu_mutex_locked(mutex); if (err) error_exit(err, __func__); } diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c index 59befd5..653f29f 100644 --- a/util/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c @@ -19,6 +19,7 @@ #include "qemu-common.h" #include "qemu/thread.h" #include "qemu/notify.h" +#include "trace.h" #include <process.h> static bool name_threads; @@ -55,6 +56,7 @@ void qemu_mutex_destroy(QemuMutex *mutex) void qemu_mutex_lock(QemuMutex *mutex) { AcquireSRWLockExclusive(&mutex->lock); + trace_qemu_mutex_locked(mutex); } int qemu_mutex_trylock(QemuMutex *mutex) @@ -62,11 +64,16 @@ int qemu_mutex_trylock(QemuMutex *mutex) int owned; owned = TryAcquireSRWLockExclusive(&mutex->lock); - return !owned; + if (owned) { + trace_qemu_mutex_locked(mutex); + return 0; + } + return -EBUSY; } void qemu_mutex_unlock(QemuMutex *mutex) { + trace_qemu_mutex_unlocked(mutex); ReleaseSRWLockExclusive(&mutex->lock); } @@ -118,7 +125,9 @@ void qemu_cond_broadcast(QemuCond *cond) void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) { + trace_qemu_mutex_unlocked(mutex); SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0); + trace_qemu_mutex_locked(mutex); } void qemu_sem_init(QemuSemaphore *sem, int init) diff --git a/util/trace-events b/util/trace-events index b44ef4f..fa540c6 100644 --- a/util/trace-events +++ b/util/trace-events @@ -55,3 +55,7 @@ lockcnt_futex_wait_prepare(const void *lockcnt, int expected, int new) "lockcnt lockcnt_futex_wait(const void *lockcnt, int val) "lockcnt %p waiting on %d" lockcnt_futex_wait_resume(const void *lockcnt, int new) "lockcnt %p after wait: %d" lockcnt_futex_wake(const void *lockcnt) "lockcnt %p waking up one waiter" + +# util/qemu-thread-posix.c +qemu_mutex_locked(void *lock) "locked mutex %p" +qemu_mutex_unlocked(void *lock) "unlocked mutex %p" @@ -3727,26 +3727,21 @@ int main(int argc, char **argv, char **envp) qdev_prop_register_global(&kvm_pit_lost_tick_policy); break; } - case QEMU_OPTION_accel: + case QEMU_OPTION_accel: { + QemuOpts *accel_opts; + accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"), optarg, true); optarg = qemu_opt_get(accel_opts, "accel"); - - olist = qemu_find_opts("machine"); - if (strcmp("kvm", optarg) == 0) { - qemu_opts_parse_noisily(olist, "accel=kvm", false); - } else if (strcmp("xen", optarg) == 0) { - qemu_opts_parse_noisily(olist, "accel=xen", false); - } else if (strcmp("tcg", optarg) == 0) { - qemu_opts_parse_noisily(olist, "accel=tcg", false); - } else { - if (!is_help_option(optarg)) { - error_printf("Unknown accelerator: %s", optarg); - } - error_printf("Supported accelerators: kvm, xen, tcg\n"); + if (!optarg || is_help_option(optarg)) { + error_printf("Possible accelerators: kvm, xen, hax, tcg\n"); exit(1); } + accel_opts = qemu_opts_create(qemu_find_opts("machine"), NULL, + false, &error_abort); + qemu_opt_set(accel_opts, "accel", optarg, &error_abort); break; + } case QEMU_OPTION_usb: olist = qemu_find_opts("machine"); qemu_opts_parse_noisily(olist, "usb=on", false); @@ -4729,6 +4724,7 @@ int main(int argc, char **argv, char **envp) audio_cleanup(); monitor_cleanup(); qemu_chr_cleanup(); + /* TODO: unref root container, check all devices are ok */ return 0; } |