diff options
42 files changed, 637 insertions, 183 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 554be84b32..69003cdc3c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -174,7 +174,6 @@ F: include/hw/arm/smmu* AVR TCG CPUs M: Michael Rolnik <mrolnik@gmail.com> -R: Sarah Harris <S.E.Harris@kent.ac.uk> S: Maintained F: docs/system/target-avr.rst F: gdb-xml/avr-cpu.xml @@ -308,8 +307,8 @@ F: linux-user/host/riscv32/ F: linux-user/host/riscv64/ RENESAS RX CPUs -M: Yoshinori Sato <ysato@users.sourceforge.jp> -S: Odd Fixes +R: Yoshinori Sato <ysato@users.sourceforge.jp> +S: Orphan F: target/rx/ S390 TCG CPUs @@ -323,8 +322,8 @@ F: tests/tcg/s390x/ L: qemu-s390x@nongnu.org SH4 TCG CPUs -M: Yoshinori Sato <ysato@users.sourceforge.jp> -S: Odd Fixes +R: Yoshinori Sato <ysato@users.sourceforge.jp> +S: Orphan F: target/sh4/ F: hw/sh4/ F: disas/sh4.c @@ -1045,7 +1044,6 @@ AVR Machines AVR MCUs M: Michael Rolnik <mrolnik@gmail.com> -R: Sarah Harris <S.E.Harris@kent.ac.uk> S: Maintained F: default-configs/*/avr-softmmu.mak F: hw/avr/ @@ -1058,7 +1056,6 @@ F: hw/misc/avr_power.c Arduino M: Philippe Mathieu-Daudé <f4bug@amsat.org> -R: Sarah Harris <S.E.Harris@kent.ac.uk> S: Maintained F: hw/avr/arduino.c @@ -1408,8 +1405,8 @@ F: include/hw/*/*sifive*.h RX Machines ----------- rx-gdbsim -M: Yoshinori Sato <ysato@users.sourceforge.jp> -S: Odd Fixes +R: Yoshinori Sato <ysato@users.sourceforge.jp> +S: Orphan F: docs/system/target-rx.rst F: hw/rx/rx-gdbsim.c F: tests/acceptance/machine_rx_gdbsim.py @@ -1417,7 +1414,7 @@ F: tests/acceptance/machine_rx_gdbsim.py SH4 Machines ------------ R2D -M: Yoshinori Sato <ysato@users.sourceforge.jp> +R: Yoshinori Sato <ysato@users.sourceforge.jp> R: Magnus Damm <magnus.damm@gmail.com> S: Odd Fixes F: hw/char/sh_serial.c @@ -1428,7 +1425,7 @@ F: hw/timer/sh_timer.c F: include/hw/sh4/sh_intc.h Shix -M: Yoshinori Sato <ysato@users.sourceforge.jp> +R: Yoshinori Sato <ysato@users.sourceforge.jp> R: Magnus Damm <magnus.damm@gmail.com> S: Odd Fixes F: hw/block/tc58128.c @@ -1516,6 +1513,7 @@ L: qemu-s390x@nongnu.org S390 PCI M: Matthew Rosato <mjrosato@linux.ibm.com> +M: Eric Farman <farman@linux.ibm.com> S: Supported F: hw/s390x/s390-pci* F: include/hw/s390x/s390-pci* @@ -1727,8 +1725,7 @@ F: tests/qtest/acpi-utils.[hc] F: tests/data/acpi/ ACPI/HEST/GHES -R: Dongjiu Geng <gengdongjiu@huawei.com> -R: Xiang Zheng <zhengxiang9@huawei.com> +R: Dongjiu Geng <gengdongjiu1@gmail.com> L: qemu-arm@nongnu.org S: Maintained F: hw/acpi/ghes.c @@ -1830,6 +1827,7 @@ F: docs/igd-assign.txt vfio-ccw M: Cornelia Huck <cohuck@redhat.com> M: Eric Farman <farman@linux.ibm.com> +M: Matthew Rosato <mjrosato@linux.ibm.com> S: Supported F: hw/vfio/ccw.c F: hw/s390x/s390-ccw.c @@ -1839,10 +1837,9 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next L: qemu-s390x@nongnu.org vfio-ap -M: Christian Borntraeger <borntraeger@de.ibm.com> M: Tony Krowiak <akrowiak@linux.ibm.com> M: Halil Pasic <pasic@linux.ibm.com> -M: Pierre Morel <pmorel@linux.ibm.com> +M: Jason Herne <jjherne@linux.ibm.com> S: Supported F: hw/s390x/ap-device.c F: hw/s390x/ap-bridge.c @@ -1919,6 +1916,7 @@ F: tools/virtiofsd/* F: hw/virtio/vhost-user-fs* F: include/hw/virtio/vhost-user-fs.h F: docs/tools/virtiofsd.rst +L: virtio-fs@redhat.com virtio-input M: Gerd Hoffmann <kraxel@redhat.com> @@ -2183,7 +2181,7 @@ F: include/hw/*/*xive* F: docs/*/*xive* Renesas peripherals -M: Yoshinori Sato <ysato@users.sourceforge.jp> +R: Yoshinori Sato <ysato@users.sourceforge.jp> R: Magnus Damm <magnus.damm@gmail.com> S: Odd Fixes F: hw/char/renesas_sci.c @@ -2195,8 +2193,8 @@ F: include/hw/sh4/sh.h F: include/hw/timer/renesas_*.h Renesas RX peripherals -M: Yoshinori Sato <ysato@users.sourceforge.jp> -S: Odd Fixes +R: Yoshinori Sato <ysato@users.sourceforge.jp> +S: Orphan F: hw/intc/rx_icu.c F: hw/rx/ F: include/hw/intc/rx_icu.h @@ -2727,6 +2725,7 @@ F: tests/vmstate-static-checker-data/ F: tests/qtest/migration-test.c F: docs/devel/migration.rst F: qapi/migration.json +F: tests/migration/ D-Bus M: Marc-André Lureau <marcandre.lureau@redhat.com> @@ -2822,7 +2821,8 @@ Yank feature M: Lukas Straub <lukasstraub2@web.de> S: Odd fixes F: util/yank.c -F: stubs/yank.c +F: migration/yank_functions* +F: tests/unit/test-yank.c F: include/qemu/yank.h F: qapi/yank.json diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c index 2a0d2e4a31..9cfd758c42 100644 --- a/backends/dbus-vmstate.c +++ b/backends/dbus-vmstate.c @@ -204,6 +204,8 @@ static int dbus_vmstate_post_load(void *opaque, int version_id) m = g_memory_input_stream_new_from_data(self->data, self->data_size, NULL); s = g_data_input_stream_new(m); g_data_input_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); + g_buffered_input_stream_set_buffer_size(G_BUFFERED_INPUT_STREAM(s), + DBUS_VMSTATE_SIZE_LIMIT); nelem = g_data_input_stream_read_uint32(s, NULL, &err); if (err) { @@ -244,11 +246,23 @@ static int dbus_vmstate_post_load(void *opaque, int version_id) } len = g_data_input_stream_read_uint32(s, NULL, &err); + if (len > DBUS_VMSTATE_SIZE_LIMIT) { + error_report("%s: Invalid vmstate size: %u", __func__, len); + return -1; + } + + g_buffered_input_stream_fill(G_BUFFERED_INPUT_STREAM(s), len, NULL, + &err); + if (err) { + goto error; + } + avail = g_buffered_input_stream_get_available( G_BUFFERED_INPUT_STREAM(s)); - - if (len > DBUS_VMSTATE_SIZE_LIMIT || len > avail) { - error_report("%s: Invalid vmstate size: %u", __func__, len); + if (len > avail) { + error_report("%s: Not enough data available to load for Id: '%s'. " + "Available data size: %zu, Actual vmstate size: %u", + __func__, id, avail, len); return -1; } diff --git a/chardev/char-socket.c b/chardev/char-socket.c index f618bdec28..daa89fe5d1 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -402,6 +402,13 @@ static void remove_hup_source(SocketChardev *s) } } +static void char_socket_yank_iochannel(void *opaque) +{ + QIOChannel *ioc = QIO_CHANNEL(opaque); + + qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); +} + static void tcp_chr_free_connection(Chardev *chr) { SocketChardev *s = SOCKET_CHARDEV(chr); @@ -424,7 +431,7 @@ static void tcp_chr_free_connection(Chardev *chr) (s->state == TCP_CHARDEV_STATE_CONNECTING || s->state == TCP_CHARDEV_STATE_CONNECTED)) { yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label), - yank_generic_iochannel, + char_socket_yank_iochannel, QIO_CHANNEL(s->sioc)); } object_unref(OBJECT(s->sioc)); @@ -946,7 +953,7 @@ static int tcp_chr_add_client(Chardev *chr, int fd) tcp_chr_set_client_ioc_name(chr, sioc); if (s->registered_yank) { yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), - yank_generic_iochannel, + char_socket_yank_iochannel, QIO_CHANNEL(sioc)); } ret = tcp_chr_new_client(chr, sioc); @@ -965,7 +972,7 @@ static void tcp_chr_accept(QIONetListener *listener, tcp_chr_set_client_ioc_name(chr, cioc); if (s->registered_yank) { yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), - yank_generic_iochannel, + char_socket_yank_iochannel, QIO_CHANNEL(cioc)); } tcp_chr_new_client(chr, cioc); @@ -985,7 +992,7 @@ static int tcp_chr_connect_client_sync(Chardev *chr, Error **errp) } if (s->registered_yank) { yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), - yank_generic_iochannel, + char_socket_yank_iochannel, QIO_CHANNEL(sioc)); } tcp_chr_new_client(chr, sioc); @@ -1005,7 +1012,7 @@ static void tcp_chr_accept_server_sync(Chardev *chr) tcp_chr_set_client_ioc_name(chr, sioc); if (s->registered_yank) { yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), - yank_generic_iochannel, + char_socket_yank_iochannel, QIO_CHANNEL(sioc)); } tcp_chr_new_client(chr, sioc); @@ -1119,7 +1126,13 @@ static void char_socket_finalize(Object *obj) } g_free(s->tls_authz); if (s->registered_yank) { - yank_unregister_instance(CHARDEV_YANK_INSTANCE(chr->label)); + /* + * In the chardev-change special-case, we shouldn't unregister the yank + * instance, as it still may be needed. + */ + if (!chr->handover_yank_instance) { + yank_unregister_instance(CHARDEV_YANK_INSTANCE(chr->label)); + } } qemu_chr_be_event(chr, CHR_EVENT_CLOSED); @@ -1138,7 +1151,7 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque) tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); if (s->registered_yank) { yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label), - yank_generic_iochannel, + char_socket_yank_iochannel, QIO_CHANNEL(sioc)); } check_report_connect_error(chr, err); @@ -1176,7 +1189,7 @@ static void tcp_chr_connect_client_async(Chardev *chr) tcp_chr_set_client_ioc_name(chr, sioc); if (s->registered_yank) { yank_register_function(CHARDEV_YANK_INSTANCE(chr->label), - yank_generic_iochannel, + char_socket_yank_iochannel, QIO_CHANNEL(sioc)); } /* @@ -1417,8 +1430,14 @@ static void qmp_chardev_open_socket(Chardev *chr, qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS); } - if (!yank_register_instance(CHARDEV_YANK_INSTANCE(chr->label), errp)) { - return; + /* + * In the chardev-change special-case, we shouldn't register a new yank + * instance, as there already may be one. + */ + if (!chr->handover_yank_instance) { + if (!yank_register_instance(CHARDEV_YANK_INSTANCE(chr->label), errp)) { + return; + } } s->registered_yank = true; @@ -1560,6 +1579,8 @@ static void char_socket_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); + cc->supports_yank = true; + cc->parse = qemu_chr_parse_socket; cc->open = qmp_chardev_open_socket; cc->chr_wait_connected = tcp_chr_wait_connected; diff --git a/chardev/char.c b/chardev/char.c index 140d6d9d36..398f09df19 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -39,6 +39,7 @@ #include "qemu/option.h" #include "qemu/id.h" #include "qemu/coroutine.h" +#include "qemu/yank.h" #include "chardev-internal.h" @@ -266,6 +267,7 @@ static void char_init(Object *obj) { Chardev *chr = CHARDEV(obj); + chr->handover_yank_instance = false; chr->logfd = -1; qemu_mutex_init(&chr->chr_write_lock); @@ -959,6 +961,7 @@ void qemu_chr_set_feature(Chardev *chr, static Chardev *chardev_new(const char *id, const char *typename, ChardevBackend *backend, GMainContext *gcontext, + bool handover_yank_instance, Error **errp) { Object *obj; @@ -967,15 +970,19 @@ static Chardev *chardev_new(const char *id, const char *typename, bool be_opened = true; assert(g_str_has_prefix(typename, "chardev-")); + assert(id); obj = object_new(typename); chr = CHARDEV(obj); + chr->handover_yank_instance = handover_yank_instance; chr->label = g_strdup(id); chr->gcontext = gcontext; qemu_char_open(chr, backend, &be_opened, &local_err); if (local_err) { - goto end; + error_propagate(errp, local_err); + object_unref(obj); + return NULL; } if (!chr->filename) { @@ -985,22 +992,6 @@ static Chardev *chardev_new(const char *id, const char *typename, qemu_chr_be_event(chr, CHR_EVENT_OPENED); } - if (id) { - object_property_try_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; } @@ -1009,6 +1000,7 @@ Chardev *qemu_chardev_new(const char *id, const char *typename, GMainContext *gcontext, Error **errp) { + Chardev *chr; g_autofree char *genid = NULL; if (!id) { @@ -1016,7 +1008,19 @@ Chardev *qemu_chardev_new(const char *id, const char *typename, id = genid; } - return chardev_new(id, typename, backend, gcontext, errp); + chr = chardev_new(id, typename, backend, gcontext, false, errp); + if (!chr) { + return NULL; + } + + if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr), + errp)) { + object_unref(OBJECT(chr)); + return NULL; + } + object_unref(OBJECT(chr)); + + return chr; } ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, @@ -1032,11 +1036,18 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)), - backend, NULL, errp); + backend, NULL, false, errp); if (!chr) { return NULL; } + if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr), + errp)) { + object_unref(OBJECT(chr)); + return NULL; + } + object_unref(OBJECT(chr)); + ret = g_new0(ChardevReturn, 1); if (CHARDEV_IS_PTY(chr)) { ret->pty = g_strdup(chr->filename + 4); @@ -1050,9 +1061,10 @@ ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, Error **errp) { CharBackend *be; - const ChardevClass *cc; + const ChardevClass *cc, *cc_new; Chardev *chr, *chr_new; bool closed_sent = false; + bool handover_yank_instance; ChardevReturn *ret; chr = qemu_chr_find(id); @@ -1084,17 +1096,23 @@ ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, return NULL; } - cc = char_get_class(ChardevBackendKind_str(backend->type), errp); - if (!cc) { + cc = CHARDEV_GET_CLASS(chr); + cc_new = char_get_class(ChardevBackendKind_str(backend->type), errp); + if (!cc_new) { return NULL; } - chr_new = chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)), - backend, chr->gcontext, errp); + /* + * The new chardev should not register a yank instance if the current + * chardev has registered one already. + */ + handover_yank_instance = cc->supports_yank && cc_new->supports_yank; + + chr_new = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc_new)), + backend, chr->gcontext, handover_yank_instance, errp); if (!chr_new) { return NULL; } - chr_new->label = g_strdup(id); if (chr->be_open && !chr_new->be_open) { qemu_chr_be_event(chr, CHR_EVENT_CLOSED); @@ -1115,6 +1133,15 @@ ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, return NULL; } + /* change successfull, clean up */ + chr_new->handover_yank_instance = false; + + /* + * When the old chardev is freed, it should not unregister the yank + * instance if the new chardev needs it. + */ + chr->handover_yank_instance = handover_yank_instance; + object_unparent(OBJECT(chr)); object_property_add_child(get_chardevs_root(), chr_new->label, OBJECT(chr_new)); diff --git a/configure b/configure index 535e6a9269..8275df1506 100755 --- a/configure +++ b/configure @@ -365,7 +365,7 @@ tcg_interpreter="false" bigendian="no" mingw32="no" gcov="no" -EXESUF="$default_feature" +EXESUF="" HOST_DSOSUF=".so" modules="no" module_upgrades="no" diff --git a/docs/defs.rst.inc b/docs/defs.rst.inc index 48d05aaf33..52d6454b93 100644 --- a/docs/defs.rst.inc +++ b/docs/defs.rst.inc @@ -10,6 +10,6 @@ incorrectly in boldface. .. |qemu_system| replace:: qemu-system-x86_64 -.. |qemu_system_x86| replace:: qemu_system-x86_64 +.. |qemu_system_x86| replace:: qemu-system-x86_64 .. |I2C| replace:: I\ :sup:`2`\ C .. |I2S| replace:: I\ :sup:`2`\ S diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index 69ce3087e3..7ef36f42d0 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -426,14 +426,6 @@ Built by configure: build outputs. Variables which are potentially different for each emulator target are defined by the next file... -`$TARGET-NAME/config-target.mak` - TARGET-NAME is the name of a system or userspace emulator, for example, - x86_64-softmmu denotes the system emulator for the x86_64 architecture. - This file contains the variables which need to vary on a per-target - basis. For example, it will indicate whether KVM or Xen are enabled for - the target and any other potential custom libraries needed for linking - the target. - Built by Meson: diff --git a/docs/devel/code-of-conduct.rst b/docs/devel/code-of-conduct.rst new file mode 100644 index 0000000000..277b5250d1 --- /dev/null +++ b/docs/devel/code-of-conduct.rst @@ -0,0 +1,60 @@ +Code of Conduct +=============== + +The QEMU community is made up of a mixture of professionals and +volunteers from all over the world. Diversity is one of our strengths, +but it can also lead to communication issues and unhappiness. +To that end, we have a few ground rules that we ask people to adhere to. + +* Be welcoming. We are committed to making participation in this project + a harassment-free experience for everyone, regardless of level of + experience, gender, gender identity and expression, sexual orientation, + disability, personal appearance, body size, race, ethnicity, age, religion, + or nationality. + +* Be respectful. Not all of us will agree all the time. Disagreements, both + social and technical, happen all the time and the QEMU community is no + exception. When we disagree, we try to understand why. It is important that + we resolve disagreements and differing views constructively. Members of the + QEMU community should be respectful when dealing with other contributors as + well as with people outside the QEMU community and with users of QEMU. + +Harassment and other exclusionary behavior are not acceptable. A community +where people feel uncomfortable or threatened is neither welcoming nor +respectful. Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery + +* Personal attacks + +* Trolling or insulting/derogatory comments + +* Public or private harassment + +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission + +This isn't an exhaustive list of things that you can't do. Rather, take +it in the spirit in which it's intended: a guide to make it easier to +be excellent to each other. + +This code of conduct applies to all spaces managed by the QEMU project. +This includes IRC, the mailing lists, the issue tracker, community +events, and any other forums created by the project team which the +community uses for communication. This code of conduct also applies +outside these spaces, when an individual acts as a representative or a +member of the project or its community. + +By adopting this code of conduct, project maintainers commit themselves +to fairly and consistently applying these principles to every aspect of +managing this project. If you believe someone is violating the code of +conduct, please read the :ref:`conflict-resolution` document for +information about how to proceed. + +Sources +------- + +This document is based on the `Fedora Code of Conduct +<https://fedoraproject.org/code-of-conduct>`__ and the +`Contributor Covenant version 1.3.0 +<https://www.contributor-covenant.org/version/1/3/0/code-of-conduct/>`__. diff --git a/docs/devel/conflict-resolution.rst b/docs/devel/conflict-resolution.rst new file mode 100644 index 0000000000..bb25f61865 --- /dev/null +++ b/docs/devel/conflict-resolution.rst @@ -0,0 +1,80 @@ +.. _conflict-resolution: + +Conflict Resolution Policy +========================== + +Conflicts in the community can take many forms, from someone having a +bad day and using harsh and hurtful language on the mailing list to more +serious code of conduct violations (including sexist/racist statements +or threats of violence), and everything in between. + +For the vast majority of issues, we aim to empower individuals to first +resolve conflicts themselves, asking for help when needed, and only +after that fails to escalate further. This approach gives people more +control over the outcome of their dispute. + +How we resolve conflicts +------------------------ + +If you are experiencing conflict, please consider first addressing the +perceived conflict directly with other involved parties, preferably through +a real-time medium such as IRC. You could also try to get a third-party (e.g. +a mutual friend, and/or someone with background on the issue, but not +involved in the conflict) to intercede or mediate. + +If this fails or if you do not feel comfortable proceeding this way, or +if the problem requires immediate escalation, report the issue to the QEMU +leadership committee by sending an email to qemu@sfconservancy.org, providing +references to the misconduct. +For very urgent topics, you can also inform one or more members through IRC. +The up-to-date list of members is `available on the QEMU wiki +<https://wiki.qemu.org/Conservancy>`__. + +Your report will be treated confidentially by the leadership committee and +not be published without your agreement. The QEMU leadership committee will +then do its best to review the incident in a timely manner, and will either +seek further information, or will make a determination on next steps. + +Remedies +-------- + +Escalating an issue to the QEMU leadership committee may result in actions +impacting one or more involved parties. In the event the leadership +committee has to intervene, here are some of the ways they might respond: + +1. Take no action. For example, if the leadership committee determines + the complaint has not been substantiated or is being made in bad faith, + or if it is deemed to be outside its purview. + +2. A private reprimand, explaining the consequences of continued behavior, + to one or more involved individuals. + +3. A private reprimand and request for a private or public apology + +4. A public reprimand and request for a public apology + +5. A public reprimand plus a mandatory cooling off period. The cooling + off period may require, for example, one or more of the following: + abstaining from maintainer duties; not interacting with people involved, + including unsolicited interaction with those enforcing the guidelines + and interaction on social media; being denied participation to in-person + events. The cooling off period is voluntary but may escalate to a + temporary ban in order to enforce it. + +6. A temporary or permanent ban from some or all current and future QEMU + spaces (mailing lists, IRC, wiki, etc.), possibly including in-person + events. + +In the event of severe harassment, the leadership committee may advise that +the matter be escalated to the relevant local law enforcement agency. It +is however not the role of the leadership committee to initiate contact +with law enforcement on behalf of any of the community members involved +in an incident. + +Sources +------- + +This document was developed based on the `Drupal Conflict Resolution +Policy and Process <https://www.drupal.org/conflict-resolution>`__ +and the `Mozilla Consequence Ladder +<https://github.com/mozilla/diversity/blob/master/code-of-conduct-enforcement/consequence-ladder.md>`__ diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 7c424ea6d7..6cf7e2d233 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -1,8 +1,8 @@ .. This is the top level page for the 'devel' manual. -QEMU Developer's Guide -====================== +Developer Information +===================== This manual documents various parts of the internals of QEMU. You only need to read it if you are interested in reading or @@ -14,6 +14,8 @@ Contents: :maxdepth: 2 :includehidden: + code-of-conduct + conflict-resolution build-system style kconfig diff --git a/docs/interop/index.rst b/docs/interop/index.rst index 95d56495f6..219a5e5fc5 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -1,8 +1,8 @@ .. This is the top level page for the 'interop' manual. -QEMU System Emulation Management and Interoperability Guide -=========================================================== +System Emulation Management and Interoperability +================================================ This manual contains documents and specifications that are useful for making QEMU interoperate with other software. diff --git a/docs/specs/index.rst b/docs/specs/index.rst index 1b0eb979d5..7b08314d33 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -1,8 +1,8 @@ .. This is the top level page for the 'specs' manual -QEMU System Emulation Guest Hardware Specifications -=================================================== +System Emulation Guest Hardware Specifications +============================================== Contents: diff --git a/docs/system/index.rst b/docs/system/index.rst index 6ad9c93806..02d0707181 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -1,8 +1,8 @@ .. This is the top level page for the 'system' manual. -QEMU System Emulation User's Guide -================================== +System Emulation +================ This manual is the overall guide for users using QEMU for full system emulation (as opposed to user-mode emulation). diff --git a/docs/tools/index.rst b/docs/tools/index.rst index 3a5829c17a..d923834a73 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -1,8 +1,8 @@ .. This is the top level page for the 'tools' manual -QEMU Tools Guide -================ +Tools +===== Contents: diff --git a/docs/user/index.rst b/docs/user/index.rst index e030dadf65..a5b47459ec 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -1,8 +1,8 @@ .. This is the top level page for the 'user' manual. -QEMU User Mode Emulation User's Guide -===================================== +User Mode Emulation +=================== This manual is the overall guide for users using QEMU for user-mode emulation. In this mode, QEMU can launch diff --git a/include/chardev/char.h b/include/chardev/char.h index 4181a2784a..7c0444f90d 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -65,6 +65,8 @@ struct Chardev { char *filename; int logfd; int be_open; + /* used to coordinate the chardev-change special-case: */ + bool handover_yank_instance; GSource *gsource; GMainContext *gcontext; DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST); @@ -251,6 +253,7 @@ struct ChardevClass { ObjectClass parent_class; bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */ + bool supports_yank; void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp); void (*open)(Chardev *chr, ChardevBackend *backend, diff --git a/include/qemu/yank.h b/include/qemu/yank.h index 5b93c70cbf..5375a1f195 100644 --- a/include/qemu/yank.h +++ b/include/qemu/yank.h @@ -73,16 +73,6 @@ void yank_unregister_function(const YankInstance *instance, YankFn *func, void *opaque); -/** - * yank_generic_iochannel: Generic yank function for iochannel - * - * This is a generic yank function which will call qio_channel_shutdown on the - * provided QIOChannel. - * - * @opaque: QIOChannel to shutdown - */ -void yank_generic_iochannel(void *opaque); - #define BLOCKDEV_YANK_INSTANCE(the_node_name) (&(YankInstance) { \ .type = YANK_INSTANCE_TYPE_BLOCK_NODE, \ .u.block_node.node_name = (the_node_name) }) diff --git a/migration/channel.c b/migration/channel.c index 35fe234e9c..c9ee902021 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -20,6 +20,7 @@ #include "io/channel-tls.h" #include "io/channel-socket.h" #include "qemu/yank.h" +#include "yank_functions.h" /** * @migration_channel_process_incoming - Create new incoming migration channel @@ -38,7 +39,8 @@ void migration_channel_process_incoming(QIOChannel *ioc) ioc, object_get_typename(OBJECT(ioc))); if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET)) { - yank_register_function(MIGRATION_YANK_INSTANCE, yank_generic_iochannel, + yank_register_function(MIGRATION_YANK_INSTANCE, + migration_yank_iochannel, QIO_CHANNEL(ioc)); } @@ -76,7 +78,7 @@ void migration_channel_connect(MigrationState *s, if (!error) { if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET)) { yank_register_function(MIGRATION_YANK_INSTANCE, - yank_generic_iochannel, + migration_yank_iochannel, QIO_CHANNEL(ioc)); } diff --git a/migration/meson.build b/migration/meson.build index 9645f44005..3ecedce94d 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -6,6 +6,7 @@ migration_files = files( 'vmstate.c', 'qemu-file-channel.c', 'qemu-file.c', + 'yank_functions.c', ) softmmu_ss.add(migration_files) @@ -24,7 +25,7 @@ softmmu_ss.add(files( 'savevm.c', 'socket.c', 'tls.c', -)) +), gnutls) softmmu_ss.add(when: ['CONFIG_RDMA', rdma], if_true: files('rdma.c')) softmmu_ss.add(when: 'CONFIG_LIVE_BLOCK_MIGRATION', if_true: files('block.c')) diff --git a/migration/multifd.c b/migration/multifd.c index 03527c564c..a6677c45c8 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -27,6 +27,7 @@ #include "qemu/yank.h" #include "io/channel-socket.h" +#include "yank_functions.h" /* Multiple fd's */ @@ -989,7 +990,7 @@ int multifd_load_cleanup(Error **errp) if (object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_SOCKET) && OBJECT(p->c)->ref == 1) { yank_unregister_function(MIGRATION_YANK_INSTANCE, - yank_generic_iochannel, + migration_yank_iochannel, QIO_CHANNEL(p->c)); } diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c index afc3a7f642..876d05a540 100644 --- a/migration/qemu-file-channel.c +++ b/migration/qemu-file-channel.c @@ -28,6 +28,7 @@ #include "io/channel-socket.h" #include "qemu/iov.h" #include "qemu/yank.h" +#include "yank_functions.h" static ssize_t channel_writev_buffer(void *opaque, @@ -108,7 +109,7 @@ static int channel_close(void *opaque, Error **errp) if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) && OBJECT(ioc)->ref == 1) { yank_unregister_function(MIGRATION_YANK_INSTANCE, - yank_generic_iochannel, + migration_yank_iochannel, QIO_CHANNEL(ioc)); } object_unref(OBJECT(ioc)); diff --git a/migration/yank_functions.c b/migration/yank_functions.c new file mode 100644 index 0000000000..96c90e17dc --- /dev/null +++ b/migration/yank_functions.c @@ -0,0 +1,20 @@ +/* + * migration yank functions + * + * Copyright (c) Lukas Straub <lukasstraub2@web.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "io/channel.h" +#include "yank_functions.h" + +void migration_yank_iochannel(void *opaque) +{ + QIOChannel *ioc = QIO_CHANNEL(opaque); + + qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); +} diff --git a/migration/yank_functions.h b/migration/yank_functions.h new file mode 100644 index 0000000000..055ea22523 --- /dev/null +++ b/migration/yank_functions.h @@ -0,0 +1,17 @@ +/* + * migration yank functions + * + * Copyright (c) Lukas Straub <lukasstraub2@web.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/** + * migration_yank_iochannel: yank function for iochannel + * + * This yank function will call qio_channel_shutdown on the provided QIOChannel. + * + * @opaque: QIOChannel to shutdown + */ +void migration_yank_iochannel(void *opaque); diff --git a/qapi/qom.json b/qapi/qom.json index 2056edc072..db5ac419b1 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -733,8 +733,7 @@ '*policy': 'uint32', '*handle': 'uint32', '*cbitpos': 'uint32', - 'reduced-phys-bits': 'uint32' }, - 'if': 'defined(CONFIG_SEV)' } + 'reduced-phys-bits': 'uint32' } } ## # @ObjectType: @@ -768,14 +767,14 @@ { 'name': 'memory-backend-memfd', 'if': 'defined(CONFIG_LINUX)' }, 'memory-backend-ram', - {'name': 'pef-guest', 'if': 'defined(CONFIG_PSERIES)' }, + 'pef-guest', 'pr-manager-helper', 'rng-builtin', 'rng-egd', 'rng-random', 'secret', 'secret_keyring', - {'name': 'sev-guest', 'if': 'defined(CONFIG_SEV)' }, + 'sev-guest', 's390-pv-guest', 'throttle-group', 'tls-creds-anon', @@ -831,8 +830,7 @@ 'rng-random': 'RngRandomProperties', 'secret': 'SecretProperties', 'secret_keyring': 'SecretKeyringProperties', - 'sev-guest': { 'type': 'SevGuestProperties', - 'if': 'defined(CONFIG_SEV)' }, + 'sev-guest': 'SevGuestProperties', 'throttle-group': 'ThrottleGroupProperties', 'tls-creds-anon': 'TlsCredsAnonProperties', 'tls-creds-psk': 'TlsCredsPskProperties', diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index c3324b0f86..4479ee693a 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -17,7 +17,6 @@ #include "qemu/qemu-print.h" #include "qapi/opts-visitor.h" #include "qemu/config-file.h" -#include "qemu/qemu-print.h" bool user_creatable_complete(UserCreatable *uc, Error **errp) { @@ -159,7 +158,7 @@ char *object_property_help(const char *name, const char *type, } if (defval) { g_autofree char *def_json = g_string_free(qobject_to_json(defval), - true); + false); g_string_append_printf(str, " (default: %s)", def_json); } diff --git a/replay/replay-events.c b/replay/replay-events.c index a1c6bb934e..15983dd250 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -15,6 +15,7 @@ #include "replay-internal.h" #include "block/aio.h" #include "ui/input.h" +#include "hw/core/cpu.h" typedef struct Event { ReplayAsyncEventKind event_kind; @@ -126,6 +127,7 @@ void replay_add_event(ReplayAsyncEventKind event_kind, g_assert(replay_mutex_locked()); QTAILQ_INSERT_TAIL(&events_list, event, events); + qemu_cpu_kick(first_cpu); } void replay_bh_schedule_event(QEMUBH *bh) diff --git a/replay/replay.c b/replay/replay.c index c806fec69a..6df2abc18c 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -180,12 +180,13 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint) } if (in_checkpoint) { - /* If we are already in checkpoint, then there is no need - for additional synchronization. + /* Recursion occurs when HW event modifies timers. - Timer modification may invoke the checkpoint and - proceed to recursion. */ - return true; + Prevent performing icount warp in this case and + wait for another invocation of the checkpoint. + */ + g_assert(replay_mode == REPLAY_MODE_PLAY); + return false; } in_checkpoint = true; diff --git a/scripts/device-crash-test b/scripts/device-crash-test index 6d809ac711..8331c057b8 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -175,6 +175,7 @@ ERROR_RULE_LIST = [ {'log':r"Multiple VT220 operator consoles are not supported"}, {'log':r"core 0 already populated"}, {'log':r"could not find stage1 bootloader"}, + {'log':r"No '.*' bus found for device"}, # other exitcode=1 failures not listed above will just generate INFO messages: {'exitcode':1, 'loglevel':logging.INFO}, diff --git a/softmmu/cpu-timers.c b/softmmu/cpu-timers.c index cd38595245..34ddfa02f1 100644 --- a/softmmu/cpu-timers.c +++ b/softmmu/cpu-timers.c @@ -188,11 +188,12 @@ static const VMStateDescription icount_vmstate_adjust_timers = { static const VMStateDescription icount_vmstate_shift = { .name = "timer/icount/shift", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = icount_shift_state_needed, .fields = (VMStateField[]) { VMSTATE_INT16(icount_time_shift, TimersState), + VMSTATE_INT64(last_delta, TimersState), VMSTATE_END_OF_LIST() } }; diff --git a/softmmu/icount.c b/softmmu/icount.c index dbcd8c3594..21341a4ce4 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -176,9 +176,6 @@ static void icount_adjust(void) int64_t cur_icount; int64_t delta; - /* Protected by TimersState mutex. */ - static int64_t last_delta; - /* If the VM is not running, then do nothing. */ if (!runstate_is_running()) { return; @@ -193,20 +190,20 @@ static void icount_adjust(void) delta = cur_icount - cur_time; /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ if (delta > 0 - && last_delta + ICOUNT_WOBBLE < delta * 2 + && timers_state.last_delta + ICOUNT_WOBBLE < delta * 2 && timers_state.icount_time_shift > 0) { /* The guest is getting too far ahead. Slow time down. */ qatomic_set(&timers_state.icount_time_shift, timers_state.icount_time_shift - 1); } if (delta < 0 - && last_delta - ICOUNT_WOBBLE > delta * 2 + && timers_state.last_delta - ICOUNT_WOBBLE > delta * 2 && timers_state.icount_time_shift < MAX_ICOUNT_SHIFT) { /* The guest is getting too far behind. Speed time up. */ qatomic_set(&timers_state.icount_time_shift, timers_state.icount_time_shift + 1); } - last_delta = delta; + timers_state.last_delta = delta; qatomic_set_i64(&timers_state.qemu_icount_bias, cur_icount - (timers_state.qemu_icount << timers_state.icount_time_shift)); diff --git a/softmmu/timers-state.h b/softmmu/timers-state.h index db4e60f18f..8c262ce139 100644 --- a/softmmu/timers-state.h +++ b/softmmu/timers-state.h @@ -43,6 +43,8 @@ typedef struct TimersState { /* Conversion factor from emulated instructions to virtual clock ticks. */ int16_t icount_time_shift; + /* Icount delta used for shift auto adjust. */ + int64_t last_delta; /* Compensate for varying guest execution speed. */ int64_t qemu_icount_bias; diff --git a/stubs/meson.build b/stubs/meson.build index 8a3e804cf0..be6f6d609e 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -46,7 +46,6 @@ stub_ss.add(files('vm-stop.c')) stub_ss.add(files('win32-kbd-hook.c')) stub_ss.add(files('cpu-synchronize-state.c')) if have_block - stub_ss.add(files('yank.c')) stub_ss.add(files('replay-tools.c')) endif if have_system diff --git a/stubs/yank.c b/stubs/yank.c deleted file mode 100644 index 6090416065..0000000000 --- a/stubs/yank.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu/yank.h" - -bool yank_register_instance(const YankInstance *instance, Error **errp) -{ - return true; -} - -void yank_unregister_instance(const YankInstance *instance) -{ -} - -void yank_register_function(const YankInstance *instance, - YankFn *func, - void *opaque) -{ -} - -void yank_unregister_function(const YankInstance *instance, - YankFn *func, - void *opaque) -{ -} - -void yank_generic_iochannel(void *opaque) -{ -} - - diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index 15318a6fa7..bb0b4fb621 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -33,8 +33,7 @@ gen_semantics = executable( semantics_generated = custom_target( 'semantics_generated.pyinc', output: 'semantics_generated.pyinc', - input: gen_semantics, - command: ['@INPUT@', '@OUTPUT@'], + command: [gen_semantics, '@OUTPUT@'], ) hexagon_ss.add(semantics_generated) @@ -54,90 +53,81 @@ hexagon_ss.add(semantics_generated) shortcode_generated = custom_target( 'shortcode_generated.h.inc', output: 'shortcode_generated.h.inc', - input: 'gen_shortcode.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def], - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], + command: [python, files('gen_shortcode.py'), semantics_generated, attribs_def, '@OUTPUT@'], ) hexagon_ss.add(shortcode_generated) helper_protos_generated = custom_target( 'helper_protos_generated.h.inc', output: 'helper_protos_generated.h.inc', - input: 'gen_helper_protos.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def, gen_tcg_h], - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], + command: [python, files('gen_helper_protos.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], ) hexagon_ss.add(helper_protos_generated) tcg_funcs_generated = custom_target( 'tcg_funcs_generated.c.inc', output: 'tcg_funcs_generated.c.inc', - input: 'gen_tcg_funcs.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def, gen_tcg_h], - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], + command: [python, files('gen_tcg_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], ) hexagon_ss.add(tcg_funcs_generated) tcg_func_table_generated = custom_target( 'tcg_func_table_generated.c.inc', output: 'tcg_func_table_generated.c.inc', - input: 'gen_tcg_func_table.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def], - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], + command: [python, files('gen_tcg_func_table.py'), semantics_generated, attribs_def, '@OUTPUT@'], ) hexagon_ss.add(tcg_func_table_generated) helper_funcs_generated = custom_target( 'helper_funcs_generated.c.inc', output: 'helper_funcs_generated.c.inc', - input: 'gen_helper_funcs.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def, gen_tcg_h], - command: [python, '@INPUT@', semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], + command: [python, files('gen_helper_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, '@OUTPUT@'], ) hexagon_ss.add(helper_funcs_generated) printinsn_generated = custom_target( 'printinsn_generated.h.inc', output: 'printinsn_generated.h.inc', - input: 'gen_printinsn.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def], - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], + command: [python, files('gen_printinsn.py'), semantics_generated, attribs_def, '@OUTPUT@'], ) hexagon_ss.add(printinsn_generated) op_regs_generated = custom_target( 'op_regs_generated.h.inc', output: 'op_regs_generated.h.inc', - input: 'gen_op_regs.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def], - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], + command: [python, files('gen_op_regs.py'), semantics_generated, attribs_def, '@OUTPUT@'], ) hexagon_ss.add(op_regs_generated) op_attribs_generated = custom_target( 'op_attribs_generated.h.inc', output: 'op_attribs_generated.h.inc', - input: 'gen_op_attribs.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def], - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], + command: [python, files('gen_op_attribs.py'), semantics_generated, attribs_def, '@OUTPUT@'], ) hexagon_ss.add(op_attribs_generated) opcodes_def_generated = custom_target( 'opcodes_def_generated.h.inc', output: 'opcodes_def_generated.h.inc', - input: 'gen_opcodes_def.py', depends: [semantics_generated], depend_files: [hex_common_py, attribs_def], - command: [python, '@INPUT@', semantics_generated, attribs_def, '@OUTPUT@'], + command: [python, files('gen_opcodes_def.py'), semantics_generated, attribs_def, '@OUTPUT@'], ) hexagon_ss.add(opcodes_def_generated) @@ -154,8 +144,7 @@ gen_dectree_import = executable( iset_py = custom_target( 'iset.py', output: 'iset.py', - input: gen_dectree_import, - command: ['@INPUT@', '@OUTPUT@'], + command: [gen_dectree_import, '@OUTPUT@'], ) hexagon_ss.add(iset_py) @@ -166,9 +155,8 @@ hexagon_ss.add(iset_py) dectree_generated = custom_target( 'dectree_generated.h.inc', output: 'dectree_generated.h.inc', - input: 'dectree.py', depends: [iset_py], - command: ['PYTHONPATH=' + meson.current_build_dir(), '@INPUT@', '@OUTPUT@'], + command: ['env', 'PYTHONPATH=' + meson.current_build_dir(), files('dectree.py'), '@OUTPUT@'], ) hexagon_ss.add(dectree_generated) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index af1faf9342..880bc45561 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5061,6 +5061,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_jr(s, s->T0); break; case 3: /* lcall Ev */ + if (mod == 3) { + goto illegal_op; + } gen_op_ld_v(s, ot, s->T1, s->A0); gen_add_A0_im(s, 1 << ot); gen_op_ld_v(s, MO_16, s->T0, s->A0); @@ -5088,6 +5091,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_jr(s, s->T0); break; case 5: /* ljmp Ev */ + if (mod == 3) { + goto illegal_op; + } gen_op_ld_v(s, ot, s->T1, s->A0); gen_add_A0_im(s, 1 << ot); gen_op_ld_v(s, MO_16, s->T0, s->A0); diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index c6dce879f1..a9c81f8bd5 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -884,6 +884,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) gen_illegal_exception(dc); } else { TCGv spr = tcg_temp_new(); + + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + if (dc->delayed_branch) { + tcg_gen_mov_tl(cpu_pc, jmp_pc); + tcg_gen_discard_tl(jmp_pc); + } else { + tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); + } + dc->base.is_jmp = DISAS_EXIT; + } + tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); tcg_temp_free(spr); @@ -898,6 +910,9 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) } else { TCGv spr; + if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } /* For SR, we will need to exit the TB to recognize the new * exception state. For NPC, in theory this counts as a branch * (although the SPR only exists for use by an ICE). Save all diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 4bfe4627ba..b3bc2109da 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -123,7 +123,8 @@ if have_system 'test-util-sockets': ['socket-helpers.c'], 'test-base64': [], 'test-bufferiszero': [], - 'test-vmstate': [migration, io] + 'test-vmstate': [migration, io], + 'test-yank': ['socket-helpers.c', qom, io, chardev] } if 'CONFIG_INOTIFY1' in config_host tests += {'test-util-filemonitor': []} diff --git a/tests/unit/test-yank.c b/tests/unit/test-yank.c new file mode 100644 index 0000000000..2383d2908c --- /dev/null +++ b/tests/unit/test-yank.c @@ -0,0 +1,249 @@ +/* + * Tests for QEMU yank feature + * + * Copyright (c) Lukas Straub <lukasstraub2@web.de> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib/gstdio.h> + +#include "qemu/config-file.h" +#include "qemu/module.h" +#include "qemu/option.h" +#include "chardev/char-fe.h" +#include "sysemu/sysemu.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-char.h" +#include "qapi/qapi-types-char.h" +#include "qapi/qapi-commands-yank.h" +#include "qapi/qapi-types-yank.h" +#include "io/channel-socket.h" +#include "socket-helpers.h" + +typedef struct { + SocketAddress *addr; + bool old_yank; + bool new_yank; + bool fail; +} CharChangeTestConfig; + +static int chardev_change(void *opaque) +{ + return 0; +} + +static bool is_yank_instance_registered(void) +{ + YankInstanceList *list; + bool ret; + + list = qmp_query_yank(&error_abort); + + ret = !!list; + + qapi_free_YankInstanceList(list); + + return ret; +} + +static gpointer accept_thread(gpointer data) +{ + QIOChannelSocket *ioc = data; + QIOChannelSocket *cioc; + + cioc = qio_channel_socket_accept(ioc, &error_abort); + object_unref(OBJECT(cioc)); + + return NULL; +} + +static void char_change_test(gconstpointer opaque) +{ + CharChangeTestConfig *conf = (gpointer) opaque; + SocketAddress *addr; + Chardev *chr; + CharBackend be; + ChardevReturn *ret; + QIOChannelSocket *ioc; + QemuThread thread; + + /* + * Setup a listener socket and determine its address + * so we know the TCP port for the client later + */ + ioc = qio_channel_socket_new(); + g_assert_nonnull(ioc); + qio_channel_socket_listen_sync(ioc, conf->addr, 1, &error_abort); + addr = qio_channel_socket_get_local_address(ioc, &error_abort); + g_assert_nonnull(addr); + + ChardevBackend backend[2] = { + /* doesn't support yank */ + { .type = CHARDEV_BACKEND_KIND_NULL }, + /* supports yank */ + { + .type = CHARDEV_BACKEND_KIND_SOCKET, + .u.socket.data = &(ChardevSocket) { + .addr = &(SocketAddressLegacy) { + .type = SOCKET_ADDRESS_LEGACY_KIND_INET, + .u.inet.data = &addr->u.inet + }, + .has_server = true, + .server = false + } + } }; + + ChardevBackend fail_backend[2] = { + /* doesn't support yank */ + { + .type = CHARDEV_BACKEND_KIND_UDP, + .u.udp.data = &(ChardevUdp) { + .remote = &(SocketAddressLegacy) { + .type = SOCKET_ADDRESS_LEGACY_KIND_UNIX, + .u.q_unix.data = &(UnixSocketAddress) { + .path = (char *)"" + } + } + } + }, + /* supports yank */ + { + .type = CHARDEV_BACKEND_KIND_SOCKET, + .u.socket.data = &(ChardevSocket) { + .addr = &(SocketAddressLegacy) { + .type = SOCKET_ADDRESS_LEGACY_KIND_INET, + .u.inet.data = &(InetSocketAddress) { + .host = (char *)"127.0.0.1", + .port = (char *)"0" + } + }, + .has_server = true, + .server = false + } + } }; + + g_assert(!is_yank_instance_registered()); + + if (conf->old_yank) { + qemu_thread_create(&thread, "accept", accept_thread, + ioc, QEMU_THREAD_JOINABLE); + } + + ret = qmp_chardev_add("chardev", &backend[conf->old_yank], &error_abort); + qapi_free_ChardevReturn(ret); + chr = qemu_chr_find("chardev"); + g_assert_nonnull(chr); + + g_assert(is_yank_instance_registered() == conf->old_yank); + + qemu_chr_wait_connected(chr, &error_abort); + if (conf->old_yank) { + qemu_thread_join(&thread); + } + + qemu_chr_fe_init(&be, chr, &error_abort); + /* allow chardev-change */ + qemu_chr_fe_set_handlers(&be, NULL, NULL, + NULL, chardev_change, NULL, NULL, true); + + if (conf->fail) { + g_setenv("QTEST_SILENT_ERRORS", "1", 1); + ret = qmp_chardev_change("chardev", &fail_backend[conf->new_yank], + NULL); + g_assert_null(ret); + g_assert(be.chr == chr); + g_assert(is_yank_instance_registered() == conf->old_yank); + g_unsetenv("QTEST_SILENT_ERRORS"); + } else { + if (conf->new_yank) { + qemu_thread_create(&thread, "accept", accept_thread, + ioc, QEMU_THREAD_JOINABLE); + } + ret = qmp_chardev_change("chardev", &backend[conf->new_yank], + &error_abort); + if (conf->new_yank) { + qemu_thread_join(&thread); + } + g_assert_nonnull(ret); + g_assert(be.chr != chr); + g_assert(is_yank_instance_registered() == conf->new_yank); + } + + object_unparent(OBJECT(be.chr)); + object_unref(OBJECT(ioc)); + qapi_free_ChardevReturn(ret); + qapi_free_SocketAddress(addr); +} + +static SocketAddress tcpaddr = { + .type = SOCKET_ADDRESS_TYPE_INET, + .u.inet.host = (char *)"127.0.0.1", + .u.inet.port = (char *)"0", +}; + +int main(int argc, char **argv) +{ + bool has_ipv4, has_ipv6; + + qemu_init_main_loop(&error_abort); + socket_init(); + + g_test_init(&argc, &argv, NULL); + + if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { + g_printerr("socket_check_protocol_support() failed\n"); + goto end; + } + + if (!has_ipv4) { + goto end; + } + + module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_chardev_opts); + + g_test_add_data_func("/yank/char_change/success/to_yank", + &(CharChangeTestConfig) { .addr = &tcpaddr, + .old_yank = false, + .new_yank = true, + .fail = false }, + char_change_test); + g_test_add_data_func("/yank/char_change/fail/to_yank", + &(CharChangeTestConfig) { .addr = &tcpaddr, + .old_yank = false, + .new_yank = true, + .fail = true }, + char_change_test); + + g_test_add_data_func("/yank/char_change/success/yank_to_yank", + &(CharChangeTestConfig) { .addr = &tcpaddr, + .old_yank = true, + .new_yank = true, + .fail = false }, + char_change_test); + g_test_add_data_func("/yank/char_change/fail/yank_to_yank", + &(CharChangeTestConfig) { .addr = &tcpaddr, + .old_yank = true, + .new_yank = true, + .fail = true }, + char_change_test); + + g_test_add_data_func("/yank/char_change/success/from_yank", + &(CharChangeTestConfig) { .addr = &tcpaddr, + .old_yank = true, + .new_yank = false, + .fail = false }, + char_change_test); + g_test_add_data_func("/yank/char_change/fail/from_yank", + &(CharChangeTestConfig) { .addr = &tcpaddr, + .old_yank = true, + .new_yank = false, + .fail = true }, + char_change_test); + +end: + return g_test_run(); +} diff --git a/util/compatfd.c b/util/compatfd.c index ee47dd8089..174f394533 100644 --- a/util/compatfd.c +++ b/util/compatfd.c @@ -20,8 +20,7 @@ #include <sys/syscall.h> #endif -struct sigfd_compat_info -{ +struct sigfd_compat_info { sigset_t mask; int fd; }; @@ -53,8 +52,9 @@ static void *sigwait_compat(void *opaque) len = write(info->fd, (char *)&buffer + offset, sizeof(buffer) - offset); - if (len == -1 && errno == EINTR) + if (len == -1 && errno == EINTR) { continue; + } if (len <= 0) { return NULL; diff --git a/util/meson.build b/util/meson.build index 984fba965f..510765cde4 100644 --- a/util/meson.build +++ b/util/meson.build @@ -43,6 +43,7 @@ util_ss.add(files('stats64.c')) util_ss.add(files('systemd.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('drm.c')) util_ss.add(files('guest-random.c')) +util_ss.add(files('yank.c')) if have_user util_ss.add(files('selfmap.c')) @@ -51,7 +52,6 @@ endif if have_system util_ss.add(files('crc-ccitt.c')) util_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus.c'), gio]) - util_ss.add(files('yank.c')) util_ss.add(when: 'CONFIG_LINUX', if_true: files('userfaultfd.c')) endif diff --git a/util/module.c b/util/module.c index cbe89fede6..7661d0f623 100644 --- a/util/module.c +++ b/util/module.c @@ -230,10 +230,11 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail) } } - if (!g_hash_table_add(loaded_modules, module_name)) { + if (g_hash_table_contains(loaded_modules, module_name)) { g_free(module_name); return true; } + g_hash_table_add(loaded_modules, module_name); search_dir = getenv("QEMU_MODULE_DIR"); if (search_dir != NULL) { diff --git a/util/yank.c b/util/yank.c index fc08f65209..abf47c346d 100644 --- a/util/yank.c +++ b/util/yank.c @@ -15,7 +15,6 @@ #include "qapi/qapi-commands-yank.h" #include "qapi/qapi-visit-yank.h" #include "qapi/clone-visitor.h" -#include "io/channel.h" #include "qemu/yank.h" struct YankFuncAndParam { @@ -151,13 +150,6 @@ void yank_unregister_function(const YankInstance *instance, abort(); } -void yank_generic_iochannel(void *opaque) -{ - QIOChannel *ioc = QIO_CHANNEL(opaque); - - qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -} - void qmp_yank(YankInstanceList *instances, Error **errp) { |