diff options
79 files changed, 1832 insertions, 1595 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index bd8bacc06a..d5ea7fbb8f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2356,6 +2356,7 @@ M: Paolo Bonzini <pbonzini@redhat.com> S: Maintained F: include/qemu/main-loop.h F: include/sysemu/runstate.h +F: include/sysemu/runstate-action.h F: util/main-loop.c F: util/qemu-timer.c F: softmmu/vl.c @@ -2364,6 +2365,7 @@ F: softmmu/cpus.c F: softmmu/cpu-throttle.c F: softmmu/cpu-timers.c F: softmmu/icount.c +F: softmmu/runstate-action.c F: qapi/run-state.json Read, Copy, Update (RCU) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index baaa54249d..389eaace72 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -745,7 +745,7 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start, assert(bmap_start % BITS_PER_LONG == 0); /* We should never do log_clear before log_sync */ assert(mem->dirty_bmap); - if (start_delta) { + if (start_delta || bmap_npages - size / psize) { /* Slow path - we need to manipulate a temp bitmap */ bmap_clear = bitmap_new(bmap_npages); bitmap_copy_with_src_offset(bmap_clear, mem->dirty_bmap, @@ -758,7 +758,10 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start, bitmap_clear(bmap_clear, 0, start_delta); d.dirty_bitmap = bmap_clear; } else { - /* Fast path - start address aligns well with BITS_PER_LONG */ + /* + * Fast path - both start and size align well with BITS_PER_LONG + * (or the end of memory slot) + */ d.dirty_bitmap = mem->dirty_bmap + BIT_WORD(bmap_start); } @@ -2013,7 +2016,6 @@ static int kvm_init(MachineState *ms) const KVMCapabilityInfo *missing_cap; int ret; int type = 0; - const char *kvm_type; uint64_t dirty_log_manual_caps; s = KVM_STATE(ms->accelerator); @@ -2069,13 +2071,11 @@ static int kvm_init(MachineState *ms) } s->as = g_new0(struct KVMAs, s->nr_as); - kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type"); - if (mc->kvm_type) { + if (object_property_find(OBJECT(current_machine), "kvm-type")) { + g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine), + "kvm-type", + &error_abort); type = mc->kvm_type(ms, kvm_type); - } else if (kvm_type) { - ret = -EINVAL; - fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type); - goto err; } do { diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 58aea605d8..c2c26489c7 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -685,7 +685,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, insns_left = MIN(0xffff, cpu->icount_budget); cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu->icount_extra = cpu->icount_budget - insns_left; - if (!cpu->icount_extra) { + if (!cpu->icount_extra && insns_left < tb->icount) { /* Execute any remaining instructions, then let the main loop * handle the next event. */ @@ -724,7 +724,7 @@ int cpu_exec(CPUState *cpu) /* prepare setjmp context for exception handling */ if (sigsetjmp(cpu->jmp_env, 0) != 0) { -#if defined(__clang__) || !QEMU_GNUC_PREREQ(4, 6) +#if defined(__clang__) /* Some compilers wrongly smash all local variables after * siglongjmp. There were bug reports for gcc 4.5.0 and clang. * Reload essential local variables here for those compilers. diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 4572b4901f..b7d50a73d4 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -2379,7 +2379,7 @@ void dump_exec_info(void) qemu_printf("Translation buffer state:\n"); /* * Report total code size including the padding and TB structs; - * otherwise users might think "-tb-size" is not honoured. + * otherwise users might think "-accel tcg,tb-size" is not honoured. * For avg host size we use the precise numbers from tb_tree_stats though. */ qemu_printf("gen code size %zu/%zu\n", diff --git a/chardev/char-mux.c b/chardev/char-mux.c index 6f980bb836..72beef29d2 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -33,6 +33,13 @@ /* MUX driver for serial I/O splitting */ +/* + * Set to false by suspend_mux_open. Open events are delayed until + * resume_mux_open. Usually suspend_mux_open is called before + * command line processing and resume_mux_open afterwards. + */ +static bool muxes_opened = true; + /* Called with chr_write_lock held. */ static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len) { @@ -237,7 +244,7 @@ void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event) MuxChardev *d = MUX_CHARDEV(chr); int i; - if (!machine_init_done) { + if (!muxes_opened) { return; } @@ -328,7 +335,7 @@ static void qemu_chr_open_mux(Chardev *chr, /* only default to opened state if we've realized the initial * set of muxes */ - *be_opened = machine_init_done; + *be_opened = muxes_opened; qemu_chr_fe_init(&d->chr, drv, errp); } @@ -360,19 +367,42 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend, * mux will receive CHR_EVENT_OPENED notifications for the BE * immediately. */ -static int open_muxes(Chardev *chr) +static void open_muxes(Chardev *chr) { /* send OPENED to all already-attached FEs */ mux_chr_send_all_event(chr, CHR_EVENT_OPENED); + /* * mark mux as OPENED so any new FEs will immediately receive * OPENED event */ chr->be_open = 1; +} + +void suspend_mux_open(void) +{ + muxes_opened = false; +} + +static int chardev_options_parsed_cb(Object *child, void *opaque) +{ + Chardev *chr = (Chardev *)child; + ChardevClass *class = CHARDEV_GET_CLASS(chr); + + if (!chr->be_open && class->chr_options_parsed) { + class->chr_options_parsed(chr); + } return 0; } +void resume_mux_open(void) +{ + muxes_opened = true; + object_child_foreach(get_chardevs_root(), + chardev_options_parsed_cb, NULL); +} + static void char_mux_class_init(ObjectClass *oc, void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -383,7 +413,7 @@ static void char_mux_class_init(ObjectClass *oc, void *data) cc->chr_accept_input = mux_chr_accept_input; cc->chr_add_watch = mux_chr_add_watch; cc->chr_be_event = mux_chr_be_event; - cc->chr_machine_done = open_muxes; + cc->chr_options_parsed = open_muxes; cc->chr_update_read_handler = mux_chr_update_read_handlers; } diff --git a/chardev/chardev-sysemu.c b/chardev/chardev-sysemu.c deleted file mode 100644 index eecdc615ee..0000000000 --- a/chardev/chardev-sysemu.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "sysemu/sysemu.h" -#include "chardev/char.h" -#include "qemu/error-report.h" -#include "chardev-internal.h" - -static int chardev_machine_done_notify_one(Object *child, void *opaque) -{ - Chardev *chr = (Chardev *)child; - ChardevClass *class = CHARDEV_GET_CLASS(chr); - - if (class->chr_machine_done) { - return class->chr_machine_done(chr); - } - - return 0; -} - -static void chardev_machine_done_hook(Notifier *notifier, void *unused) -{ - int ret = object_child_foreach(get_chardevs_root(), - chardev_machine_done_notify_one, NULL); - - if (ret) { - error_report("Failed to call chardev machine_done hooks"); - exit(1); - } -} - - -static Notifier chardev_machine_done_notify = { - .notify = chardev_machine_done_hook, -}; - -static void register_types(void) -{ - /* - * This must be done after machine init, since we register FEs with muxes - * as part of realize functions like serial_isa_realizefn when -nographic - * is specified. - */ - qemu_add_machine_init_done_notifier(&chardev_machine_done_notify); -} - -type_init(register_types); diff --git a/chardev/meson.build b/chardev/meson.build index 859d8b04d4..4e19722c5e 100644 --- a/chardev/meson.build +++ b/chardev/meson.build @@ -25,7 +25,7 @@ chardev_ss.add(when: 'CONFIG_WIN32', if_true: files( chardev_ss = chardev_ss.apply(config_host, strict: false) -softmmu_ss.add(files('chardev-sysemu.c', 'msmouse.c', 'wctablet.c', 'testdev.c')) +softmmu_ss.add(files('msmouse.c', 'wctablet.c', 'testdev.c')) chardev_modules = {} @@ -2137,7 +2137,6 @@ EOF # Check we support --no-pie first; we will need this for building ROMs. if compile_prog "-Werror -fno-pie" "-no-pie"; then CFLAGS_NOPIE="-fno-pie" - LDFLAGS_NOPIE="-no-pie" fi if test "$static" = "yes"; then @@ -2153,7 +2152,6 @@ if test "$static" = "yes"; then fi elif test "$pie" = "no"; then CONFIGURE_CFLAGS="$CFLAGS_NOPIE $CONFIGURE_CFLAGS" - CONFIGURE_LDFLAGS="$LDFLAGS_NOPIE $CONFIGURE_LDFLAGS" elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS" CONFIGURE_LDFLAGS="-pie $CONFIGURE_LDFLAGS" @@ -6714,7 +6712,6 @@ echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak echo "GLIB_LIBS=$glib_libs" >> $config_host_mak echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak -echo "LDFLAGS_NOPIE=$LDFLAGS_NOPIE" >> $config_host_mak echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak echo "EXESUF=$EXESUF" >> $config_host_mak echo "HOST_DSOSUF=$HOST_DSOSUF" >> $config_host_mak diff --git a/docs/meson.build b/docs/meson.build index ebd85d59f9..bb8fe4c9e4 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -9,7 +9,7 @@ endif # Check if tools are available to build documentation. build_docs = false if sphinx_build.found() - SPHINX_ARGS = [sphinx_build] + SPHINX_ARGS = ['env', 'CONFDIR=' + qemu_confdir, sphinx_build] # If we're making warnings fatal, apply this to Sphinx runs as well if get_option('werror') SPHINX_ARGS += [ '-W' ] diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 09c8f380bc..bacd76d7a5 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -75,12 +75,6 @@ The ``pretty=on|off`` switch has no effect for HMP monitors, but is silently ignored. Using the switch with HMP monitors will become an error in the future. -``-realtime`` (since 4.1) -''''''''''''''''''''''''' - -The ``-realtime mlock=on|off`` argument has been replaced by the -``-overcommit mem-lock=on|off`` argument. - RISC-V ``-bios`` (since 5.1) '''''''''''''''''''''''''''' @@ -100,19 +94,6 @@ QEMU 5.1 has three options: to the user to load all the images they need. 3. ``-bios <file>`` - Tells QEMU to load the specified file as the firmwrae. -``-tb-size`` option (since 5.0) -''''''''''''''''''''''''''''''' - -QEMU 5.0 introduced an alternative syntax to specify the size of the translation -block cache, ``-accel tcg,tb-size=``. The new syntax deprecates the -previously available ``-tb-size`` option. - -``-show-cursor`` option (since 5.0) -''''''''''''''''''''''''''''''''''' - -Use ``-display sdl,show-cursor=on`` or - ``-display gtk,show-cursor=on`` instead. - ``Configuring floppies with ``-global`` ''''''''''''''''''''''''''''''''''''''' @@ -493,230 +474,3 @@ nanoMIPS ISA The ``nanoMIPS`` ISA has never been upstreamed to any compiler toolchain. As it is hard to generate binaries for it, declare it deprecated. - - -Recently removed features -========================= - -What follows is a record of recently removed, formerly deprecated -features that serves as a record for users who have encountered -trouble after a recent upgrade. - -System emulator command line arguments --------------------------------------- - -``-net ...,name=``\ *name* (removed in 5.1) -''''''''''''''''''''''''''''''''''''''''''' - -The ``name`` parameter of the ``-net`` option was a synonym -for the ``id`` parameter, which should now be used instead. - -``-no-kvm`` (removed in 5.2) -'''''''''''''''''''''''''''' - -The ``-no-kvm`` argument was a synonym for setting ``-machine accel=tcg``. - - -QEMU Machine Protocol (QMP) commands ------------------------------------- - -``block-dirty-bitmap-add`` "autoload" parameter (since 4.2.0) -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The "autoload" parameter has been ignored since 2.12.0. All bitmaps -are automatically loaded from qcow2 images. - -``cpu-add`` (removed in 5.2) -'''''''''''''''''''''''''''' - -Use ``device_add`` for hotplugging vCPUs instead of ``cpu-add``. See -documentation of ``query-hotpluggable-cpus`` for additional details. - -Human Monitor Protocol (HMP) commands -------------------------------------- - -The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0) -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The ``[hub_id name]`` parameter tuple of the 'hostfwd_add' and -'hostfwd_remove' HMP commands has been replaced by ``netdev_id``. - -``cpu-add`` (removed in 5.2) -'''''''''''''''''''''''''''' - -Use ``device_add`` for hotplugging vCPUs instead of ``cpu-add``. See -documentation of ``query-hotpluggable-cpus`` for additional details. - -Guest Emulator ISAs -------------------- - -RISC-V ISA privilege specification version 1.09.1 (removed in 5.1) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The RISC-V ISA privilege specification version 1.09.1 has been removed. -QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these -should be used instead of the 1.09.1 version. - -System emulator CPUS --------------------- - -KVM guest support on 32-bit Arm hosts (removed in 5.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The Linux kernel has dropped support for allowing 32-bit Arm systems -to host KVM guests as of the 5.7 kernel. Accordingly, QEMU is deprecating -its support for this configuration and will remove it in a future version. -Running 32-bit guests on a 64-bit Arm host remains supported. - -RISC-V ISA Specific CPUs (removed in 5.1) -''''''''''''''''''''''''''''''''''''''''' - -The RISC-V cpus with the ISA version in the CPU name have been removed. The -four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and -``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec`` -option when using the ``rv32`` or ``rv64`` CPUs. - -RISC-V no MMU CPUs (removed in 5.1) -''''''''''''''''''''''''''''''''''' - -The RISC-V no MMU cpus have been removed. The two CPUs: ``rv32imacu-nommu`` and -``rv64imacu-nommu`` can no longer be used. Instead the MMU status can be specified -via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. - -System emulator machines ------------------------- - -``spike_v1.9.1`` and ``spike_v1.10`` (removed in 5.1) -''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The version specific Spike machines have been removed in favour of the -generic ``spike`` machine. If you need to specify an older version of the RISC-V -spec you can use the ``-cpu rv64gcsu,priv_spec=v1.10.0`` command line argument. - -mips ``r4k`` platform (removed in 5.2) -'''''''''''''''''''''''''''''''''''''' - -This machine type was very old and unmaintained. Users should use the ``malta`` -machine type instead. - -Related binaries ----------------- - -``qemu-nbd --partition`` (removed in 5.0) -''''''''''''''''''''''''''''''''''''''''' - -The ``qemu-nbd --partition $digit`` code (also spelled ``-P``) -could only handle MBR partitions, and never correctly handled logical -partitions beyond partition 5. Exporting a partition can still be -done by utilizing the ``--image-opts`` option with a raw blockdev -using the ``offset`` and ``size`` parameters layered on top of -any other existing blockdev. For example, if partition 1 is 100MiB -long starting at 1MiB, the old command:: - - qemu-nbd -t -P 1 -f qcow2 file.qcow2 - -can be rewritten as:: - - qemu-nbd -t --image-opts driver=raw,offset=1M,size=100M,file.driver=qcow2,file.file.driver=file,file.file.filename=file.qcow2 - -``qemu-img convert -n -o`` (removed in 5.1) -''''''''''''''''''''''''''''''''''''''''''' - -All options specified in ``-o`` are image creation options, so -they are now rejected when used with ``-n`` to skip image creation. - - -``qemu-img create -b bad file $size`` (removed in 5.1) -'''''''''''''''''''''''''''''''''''''''''''''''''''''' - -When creating an image with a backing file that could not be opened, -``qemu-img create`` used to issue a warning about the failure but -proceed with the image creation if an explicit size was provided. -However, as the ``-u`` option exists for this purpose, it is safer to -enforce that any failure to open the backing image (including if the -backing file is missing or an incorrect format was specified) is an -error when ``-u`` is not used. - -Command line options --------------------- - -``-smp`` (invalid topologies) (removed 5.2) -''''''''''''''''''''''''''''''''''''''''''' - -CPU topology properties should describe whole machine topology including -possible CPUs. - -However, historically it was possible to start QEMU with an incorrect topology -where *n* <= *sockets* * *cores* * *threads* < *maxcpus*, -which could lead to an incorrect topology enumeration by the guest. -Support for invalid topologies is removed, the user must ensure -topologies described with -smp include all possible cpus, i.e. -*sockets* * *cores* * *threads* = *maxcpus*. - -``-numa`` node (without memory specified) (removed 5.2) -''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Splitting RAM by default between NUMA nodes had the same issues as ``mem`` -parameter with the difference that the role of the user plays QEMU using -implicit generic or board specific splitting rule. -Use ``memdev`` with *memory-backend-ram* backend or ``mem`` (if -it's supported by used machine type) to define mapping explicitly instead. -Users of existing VMs, wishing to preserve the same RAM distribution, should -configure it explicitly using ``-numa node,memdev`` options. Current RAM -distribution can be retrieved using HMP command ``info numa`` and if separate -memory devices (pc|nv-dimm) are present use ``info memory-device`` and subtract -device memory from output of ``info numa``. - -``-numa node,mem=``\ *size* (removed in 5.1) -'''''''''''''''''''''''''''''''''''''''''''' - -The parameter ``mem`` of ``-numa node`` was used to assign a part of -guest RAM to a NUMA node. But when using it, it's impossible to manage a specified -RAM chunk on the host side (like bind it to a host node, setting bind policy, ...), -so the guest ends up with the fake NUMA configuration with suboptiomal performance. -However since 2014 there is an alternative way to assign RAM to a NUMA node -using parameter ``memdev``, which does the same as ``mem`` and adds -means to actually manage node RAM on the host side. Use parameter ``memdev`` -with *memory-backend-ram* backend as replacement for parameter ``mem`` -to achieve the same fake NUMA effect or a properly configured -*memory-backend-file* backend to actually benefit from NUMA configuration. -New machine versions (since 5.1) will not accept the option but it will still -work with old machine types. User can check the QAPI schema to see if the legacy -option is supported by looking at MachineInfo::numa-mem-supported property. - -``-mem-path`` fallback to RAM (removed in 5.0) -'''''''''''''''''''''''''''''''''''''''''''''' - -If guest RAM allocation from file pointed by ``mem-path`` failed, -QEMU was falling back to allocating from RAM, which might have resulted -in unpredictable behavior since the backing file specified by the user -as ignored. Currently, users are responsible for making sure the backing storage -specified with ``-mem-path`` can actually provide the guest RAM configured with -``-m`` and QEMU fails to start up if RAM allocation is unsuccessful. - -``-smp`` (invalid topologies) (removed 5.2) -''''''''''''''''''''''''''''''''''''''''''' - -CPU topology properties should describe whole machine topology including -possible CPUs. - -However, historically it was possible to start QEMU with an incorrect topology -where *n* <= *sockets* * *cores* * *threads* < *maxcpus*, -which could lead to an incorrect topology enumeration by the guest. -Support for invalid topologies is removed, the user must ensure -topologies described with -smp include all possible cpus, i.e. -*sockets* * *cores* * *threads* = *maxcpus*. - -``-machine enforce-config-section=on|off`` (removed 5.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -The ``enforce-config-section`` property was replaced by the -``-global migration.send-configuration={on|off}`` option. - -Block devices -------------- - -VXHS backend (removed in 5.1) -''''''''''''''''''''''''''''' - -The VXHS code does not compile since v2.12.0. It was removed in 5.1. diff --git a/docs/system/index.rst b/docs/system/index.rst index e5a35817a2..d40f72c92b 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -35,5 +35,6 @@ Contents: targets security deprecated + removed-features build-platforms license diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst new file mode 100644 index 0000000000..8b20d78a4d --- /dev/null +++ b/docs/system/removed-features.rst @@ -0,0 +1,243 @@ + +Removed features +================ + +What follows is a record of recently removed, formerly deprecated +features that serves as a record for users who have encountered +trouble after a recent upgrade. + +System emulator command line arguments +-------------------------------------- + +``-net ...,name=``\ *name* (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''''' + +The ``name`` parameter of the ``-net`` option was a synonym +for the ``id`` parameter, which should now be used instead. + +``-no-kvm`` (removed in 5.2) +'''''''''''''''''''''''''''' + +The ``-no-kvm`` argument was a synonym for setting ``-machine accel=tcg``. + +``-realtime`` (removed in 6.0) +'''''''''''''''''''''''''''''' + +The ``-realtime mlock=on|off`` argument has been replaced by the +``-overcommit mem-lock=on|off`` argument. + +``-show-cursor`` option (since 5.0) +''''''''''''''''''''''''''''''''''' + +Use ``-display sdl,show-cursor=on``, ``-display gtk,show-cursor=on`` +or ``-display default,show-cursor=on`` instead. + +``-tb-size`` option (removed in 6.0) +'''''''''''''''''''''''''''''''''''' + +QEMU 5.0 introduced an alternative syntax to specify the size of the translation +block cache, ``-accel tcg,tb-size=``. + +QEMU Machine Protocol (QMP) commands +------------------------------------ + +``block-dirty-bitmap-add`` "autoload" parameter (removed in 4.2.0) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The "autoload" parameter has been ignored since 2.12.0. All bitmaps +are automatically loaded from qcow2 images. + +``cpu-add`` (removed in 5.2) +'''''''''''''''''''''''''''' + +Use ``device_add`` for hotplugging vCPUs instead of ``cpu-add``. See +documentation of ``query-hotpluggable-cpus`` for additional details. + +Human Monitor Protocol (HMP) commands +------------------------------------- + +The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``[hub_id name]`` parameter tuple of the 'hostfwd_add' and +'hostfwd_remove' HMP commands has been replaced by ``netdev_id``. + +``cpu-add`` (removed in 5.2) +'''''''''''''''''''''''''''' + +Use ``device_add`` for hotplugging vCPUs instead of ``cpu-add``. See +documentation of ``query-hotpluggable-cpus`` for additional details. + +Guest Emulator ISAs +------------------- + +RISC-V ISA privilege specification version 1.09.1 (removed in 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The RISC-V ISA privilege specification version 1.09.1 has been removed. +QEMU supports both the newer version 1.10.0 and the ratified version 1.11.0, these +should be used instead of the 1.09.1 version. + +System emulator CPUS +-------------------- + +KVM guest support on 32-bit Arm hosts (removed in 5.2) +'''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The Linux kernel has dropped support for allowing 32-bit Arm systems +to host KVM guests as of the 5.7 kernel. Accordingly, QEMU is deprecating +its support for this configuration and will remove it in a future version. +Running 32-bit guests on a 64-bit Arm host remains supported. + +RISC-V ISA Specific CPUs (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''' + +The RISC-V cpus with the ISA version in the CPU name have been removed. The +four CPUs are: ``rv32gcsu-v1.9.1``, ``rv32gcsu-v1.10.0``, ``rv64gcsu-v1.9.1`` and +``rv64gcsu-v1.10.0``. Instead the version can be specified via the CPU ``priv_spec`` +option when using the ``rv32`` or ``rv64`` CPUs. + +RISC-V no MMU CPUs (removed in 5.1) +''''''''''''''''''''''''''''''''''' + +The RISC-V no MMU cpus have been removed. The two CPUs: ``rv32imacu-nommu`` and +``rv64imacu-nommu`` can no longer be used. Instead the MMU status can be specified +via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. + +System emulator machines +------------------------ + +``spike_v1.9.1`` and ``spike_v1.10`` (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The version specific Spike machines have been removed in favour of the +generic ``spike`` machine. If you need to specify an older version of the RISC-V +spec you can use the ``-cpu rv64gcsu,priv_spec=v1.10.0`` command line argument. + +mips ``r4k`` platform (removed in 5.2) +'''''''''''''''''''''''''''''''''''''' + +This machine type was very old and unmaintained. Users should use the ``malta`` +machine type instead. + +Related binaries +---------------- + +``qemu-nbd --partition`` (removed in 5.0) +''''''''''''''''''''''''''''''''''''''''' + +The ``qemu-nbd --partition $digit`` code (also spelled ``-P``) +could only handle MBR partitions, and never correctly handled logical +partitions beyond partition 5. Exporting a partition can still be +done by utilizing the ``--image-opts`` option with a raw blockdev +using the ``offset`` and ``size`` parameters layered on top of +any other existing blockdev. For example, if partition 1 is 100MiB +long starting at 1MiB, the old command:: + + qemu-nbd -t -P 1 -f qcow2 file.qcow2 + +can be rewritten as:: + + qemu-nbd -t --image-opts driver=raw,offset=1M,size=100M,file.driver=qcow2,file.file.driver=file,file.file.filename=file.qcow2 + +``qemu-img convert -n -o`` (removed in 5.1) +''''''''''''''''''''''''''''''''''''''''''' + +All options specified in ``-o`` are image creation options, so +they are now rejected when used with ``-n`` to skip image creation. + + +``qemu-img create -b bad file $size`` (removed in 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''' + +When creating an image with a backing file that could not be opened, +``qemu-img create`` used to issue a warning about the failure but +proceed with the image creation if an explicit size was provided. +However, as the ``-u`` option exists for this purpose, it is safer to +enforce that any failure to open the backing image (including if the +backing file is missing or an incorrect format was specified) is an +error when ``-u`` is not used. + +Command line options +-------------------- + +``-smp`` (invalid topologies) (removed 5.2) +''''''''''''''''''''''''''''''''''''''''''' + +CPU topology properties should describe whole machine topology including +possible CPUs. + +However, historically it was possible to start QEMU with an incorrect topology +where *n* <= *sockets* * *cores* * *threads* < *maxcpus*, +which could lead to an incorrect topology enumeration by the guest. +Support for invalid topologies is removed, the user must ensure +topologies described with -smp include all possible cpus, i.e. +*sockets* * *cores* * *threads* = *maxcpus*. + +``-numa`` node (without memory specified) (removed 5.2) +''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Splitting RAM by default between NUMA nodes had the same issues as ``mem`` +parameter with the difference that the role of the user plays QEMU using +implicit generic or board specific splitting rule. +Use ``memdev`` with *memory-backend-ram* backend or ``mem`` (if +it's supported by used machine type) to define mapping explicitly instead. +Users of existing VMs, wishing to preserve the same RAM distribution, should +configure it explicitly using ``-numa node,memdev`` options. Current RAM +distribution can be retrieved using HMP command ``info numa`` and if separate +memory devices (pc|nv-dimm) are present use ``info memory-device`` and subtract +device memory from output of ``info numa``. + +``-numa node,mem=``\ *size* (removed in 5.1) +'''''''''''''''''''''''''''''''''''''''''''' + +The parameter ``mem`` of ``-numa node`` was used to assign a part of +guest RAM to a NUMA node. But when using it, it's impossible to manage a specified +RAM chunk on the host side (like bind it to a host node, setting bind policy, ...), +so the guest ends up with the fake NUMA configuration with suboptiomal performance. +However since 2014 there is an alternative way to assign RAM to a NUMA node +using parameter ``memdev``, which does the same as ``mem`` and adds +means to actually manage node RAM on the host side. Use parameter ``memdev`` +with *memory-backend-ram* backend as replacement for parameter ``mem`` +to achieve the same fake NUMA effect or a properly configured +*memory-backend-file* backend to actually benefit from NUMA configuration. +New machine versions (since 5.1) will not accept the option but it will still +work with old machine types. User can check the QAPI schema to see if the legacy +option is supported by looking at MachineInfo::numa-mem-supported property. + +``-mem-path`` fallback to RAM (removed in 5.0) +'''''''''''''''''''''''''''''''''''''''''''''' + +If guest RAM allocation from file pointed by ``mem-path`` failed, +QEMU was falling back to allocating from RAM, which might have resulted +in unpredictable behavior since the backing file specified by the user +as ignored. Currently, users are responsible for making sure the backing storage +specified with ``-mem-path`` can actually provide the guest RAM configured with +``-m`` and QEMU fails to start up if RAM allocation is unsuccessful. + +``-smp`` (invalid topologies) (removed 5.2) +''''''''''''''''''''''''''''''''''''''''''' + +CPU topology properties should describe whole machine topology including +possible CPUs. + +However, historically it was possible to start QEMU with an incorrect topology +where *n* <= *sockets* * *cores* * *threads* < *maxcpus*, +which could lead to an incorrect topology enumeration by the guest. +Support for invalid topologies is removed, the user must ensure +topologies described with -smp include all possible cpus, i.e. +*sockets* * *cores* * *threads* = *maxcpus*. + +``-machine enforce-config-section=on|off`` (removed 5.2) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``enforce-config-section`` property was replaced by the +``-global migration.send-configuration={on|off}`` option. + +Block devices +------------- + +VXHS backend (removed in 5.1) +''''''''''''''''''''''''''''' + +The VXHS code did not compile since v2.12.0. It was removed in 5.1. diff --git a/hmp-commands.hx b/hmp-commands.hx index dd460eb908..470a420c2d 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -45,6 +45,7 @@ ERST .params = "", .help = "quit the emulator", .cmd = hmp_quit, + .flags = "p", }, SRST diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 4d9d47ba1c..e56c42ac22 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -1299,7 +1299,7 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info) info->kernel_filename = ms->kernel_filename; info->kernel_cmdline = ms->kernel_cmdline; info->initrd_filename = ms->initrd_filename; - info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); + info->dtb_filename = ms->dtb; info->dtb_limit = 0; /* Load the kernel. */ diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 5362c80a18..87f14140a3 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -286,10 +286,9 @@ HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp) void qmp_set_numa_node(NumaOptions *cmd, Error **errp) { - if (!runstate_check(RUN_STATE_PRECONFIG)) { - error_setg(errp, "The command is permitted only in '%s' state", - RunState_str(RUN_STATE_PRECONFIG)); - return; + if (phase_check(PHASE_MACHINE_INITIALIZED)) { + error_setg(errp, "The command is permitted only before the machine has been created"); + return; } set_numa_options(MACHINE(qdev_get_machine()), cmd, errp); diff --git a/hw/core/machine.c b/hw/core/machine.c index d7f8fdee45..05dcaf09c9 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -16,16 +16,21 @@ #include "sysemu/replay.h" #include "qemu/units.h" #include "hw/boards.h" +#include "hw/loader.h" #include "qapi/error.h" #include "qapi/qapi-visit-common.h" #include "qapi/visitor.h" #include "hw/sysbus.h" +#include "sysemu/cpus.h" #include "sysemu/sysemu.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" #include "sysemu/numa.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" #include "hw/pci/pci.h" #include "hw/mem/nvdimm.h" +#include "migration/global_state.h" #include "migration/vmstate.h" GlobalProperty hw_compat_5_2[] = {}; @@ -216,6 +221,8 @@ GlobalProperty hw_compat_2_1[] = { }; const size_t hw_compat_2_1_len = G_N_ELEMENTS(hw_compat_2_1); +MachineState *current_machine; + static char *machine_get_kernel(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); @@ -1167,17 +1174,16 @@ void machine_run_board_init(MachineState *machine) } machine_class->init(machine); + phase_advance(PHASE_MACHINE_INITIALIZED); } static NotifierList machine_init_done_notifiers = NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers); -bool machine_init_done; - void qemu_add_machine_init_done_notifier(Notifier *notify) { notifier_list_add(&machine_init_done_notifiers, notify); - if (machine_init_done) { + if (phase_check(PHASE_MACHINE_READY)) { notify->notify(notify, NULL); } } @@ -1187,10 +1193,48 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify) notifier_remove(notify); } -void qemu_run_machine_init_done_notifiers(void) +void qdev_machine_creation_done(void) { - machine_init_done = true; + cpu_synchronize_all_post_init(); + + if (current_machine->boot_once) { + qemu_boot_set(current_machine->boot_once, &error_fatal); + qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_order)); + } + + /* + * ok, initial machine setup is done, starting from now we can + * only create hotpluggable devices + */ + phase_advance(PHASE_MACHINE_READY); + qdev_assert_realized_properly(); + + /* TODO: once all bus devices are qdevified, this should be done + * when bus is created by qdev.c */ + /* + * TODO: If we had a main 'reset container' that the whole system + * lived in, we could reset that using the multi-phase reset + * APIs. For the moment, we just reset the sysbus, which will cause + * all devices hanging off it (and all their child buses, recursively) + * to be reset. Note that this will *not* reset any Device objects + * which are not attached to some part of the qbus tree! + */ + qemu_register_reset(resettable_cold_reset_fn, sysbus_get_default()); + notifier_list_notify(&machine_init_done_notifiers, NULL); + + if (rom_check_and_register_reset() != 0) { + exit(1); + } + + replay_start(); + + /* This checkpoint is required by replay to separate prior clock + reading from the other reads, because timer polling functions query + clock values from the log. */ + replay_checkpoint(CHECKPOINT_RESET); + qemu_system_reset(SHUTDOWN_CAUSE_NONE); + register_global_state(); } static const TypeInfo machine_info = { diff --git a/hw/core/meson.build b/hw/core/meson.build index 4a744f3b5e..032576f571 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -1,7 +1,6 @@ # core qdev-related obj files, also used by *-user and unit tests hwcore_files = files( 'bus.c', - 'fw-path-provider.c', 'hotplug.c', 'qdev-properties.c', 'qdev.c', @@ -25,6 +24,7 @@ common_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) common_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) softmmu_ss.add(files( + 'fw-path-provider.c', 'loader.c', 'machine-hmp-cmds.c', 'machine.c', diff --git a/hw/core/qdev.c b/hw/core/qdev.c index d3611e7c03..cefc5eaa0a 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -41,7 +41,6 @@ #include "migration/vmstate.h" #include "trace.h" -bool qdev_hotplug = false; static bool qdev_hot_added = false; bool qdev_hot_removed = false; @@ -404,7 +403,7 @@ void qdev_unrealize(DeviceState *dev) object_property_set_bool(OBJECT(dev), "realized", false, &error_abort); } -static int qdev_assert_realized_properly(Object *obj, void *opaque) +static int qdev_assert_realized_properly_cb(Object *obj, void *opaque) { DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE)); DeviceClass *dc; @@ -417,16 +416,10 @@ static int qdev_assert_realized_properly(Object *obj, void *opaque) return 0; } -void qdev_machine_creation_done(void) +void qdev_assert_realized_properly(void) { - /* - * ok, initial machine setup is done, starting from now we can - * only create hotpluggable devices - */ - qdev_hotplug = true; - object_child_foreach_recursive(object_get_root(), - qdev_assert_realized_properly, NULL); + qdev_assert_realized_properly_cb, NULL); } bool qdev_machine_modified(void) @@ -911,7 +904,7 @@ static void device_initfn(Object *obj) { DeviceState *dev = DEVICE(obj); - if (qdev_hotplug) { + if (phase_check(PHASE_MACHINE_READY)) { dev->hotplugged = 1; qdev_hot_added = true; } @@ -1144,6 +1137,19 @@ Object *qdev_get_machine(void) return dev; } +static MachineInitPhase machine_phase; + +bool phase_check(MachineInitPhase phase) +{ + return machine_phase >= phase; +} + +void phase_advance(MachineInitPhase phase) +{ + assert(machine_phase == phase - 1); + machine_phase = phase; +} + static const TypeInfo device_type_info = { .name = TYPE_DEVICE, .parent = TYPE_OBJECT, diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 6715ba2ff9..caaba1aa4c 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -34,6 +34,7 @@ #include "sysemu/device_tree.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" +#include "hw/boards.h" #include "hw/loader.h" #include "elf.h" #include "qemu/cutils.h" @@ -116,16 +117,14 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, const char *dtb_filename, void (*machine_cpu_reset)(MicroBlazeCPU *)) { - QemuOpts *machine_opts; const char *kernel_filename; const char *kernel_cmdline; const char *dtb_arg; char *filename = NULL; - machine_opts = qemu_get_machine_opts(); - kernel_filename = qemu_opt_get(machine_opts, "kernel"); - kernel_cmdline = qemu_opt_get(machine_opts, "append"); - dtb_arg = qemu_opt_get(machine_opts, "dtb"); + kernel_filename = current_machine->kernel_filename; + kernel_cmdline = current_machine->kernel_cmdline; + dtb_arg = current_machine->dtb; /* default to pcbios dtb as passed by machine_init */ if (!dtb_arg && dtb_filename) { filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c index 95a8697906..d9969ac148 100644 --- a/hw/nios2/boot.c +++ b/hw/nios2/boot.c @@ -39,6 +39,7 @@ #include "sysemu/device_tree.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" +#include "hw/boards.h" #include "hw/loader.h" #include "elf.h" @@ -120,16 +121,14 @@ void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base, const char *dtb_filename, void (*machine_cpu_reset)(Nios2CPU *)) { - QemuOpts *machine_opts; const char *kernel_filename; const char *kernel_cmdline; const char *dtb_arg; char *filename = NULL; - machine_opts = qemu_get_machine_opts(); - kernel_filename = qemu_opt_get(machine_opts, "kernel"); - kernel_cmdline = qemu_opt_get(machine_opts, "append"); - dtb_arg = qemu_opt_get(machine_opts, "dtb"); + kernel_filename = current_machine->kernel_filename; + kernel_cmdline = current_machine->kernel_cmdline; + dtb_arg = current_machine->dtb; /* default to pcbios dtb as passed by machine_init */ if (!dtb_arg) { filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 67e34f34d6..36491ee52b 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -179,6 +179,7 @@ static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, { PCIDevice *dev = opaque; + assert(addr + size <= dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); return pci_get_long(dev->msix_table + addr); } @@ -189,6 +190,8 @@ static void msix_table_mmio_write(void *opaque, hwaddr addr, int vector = addr / PCI_MSIX_ENTRY_SIZE; bool was_masked; + assert(addr + size <= dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); + was_masked = msix_is_masked(dev, vector); pci_set_long(dev->msix_table + addr, val); msix_handle_mask_update(dev, vector, was_masked); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 9424231542..d4349ea577 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1062,7 +1062,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_container_region, pci_dev->name); - if (qdev_hotplug) { + if (phase_check(PHASE_MACHINE_READY)) { pci_init_bus_master(pci_dev); } pci_dev->irq_state = 0; diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 072e558c2d..c64b5d08bd 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -343,9 +343,8 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms, pmc->pci_pio_base >> 32, pmc->pci_pio_base, 0x0, 0x10000, }; - QemuOpts *machine_opts = qemu_get_machine_opts(); - const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); - const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); + const char *dtb_file = machine->dtb; + const char *toplevel_compat = machine->dt_compatible; if (dtb_file) { char *filename; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index dee48a0043..489cefcb81 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3275,6 +3275,19 @@ static void spapr_instance_init(Object *obj) { SpaprMachineState *spapr = SPAPR_MACHINE(obj); SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + MachineState *ms = MACHINE(spapr); + MachineClass *mc = MACHINE_GET_CLASS(ms); + + /* + * NVDIMM support went live in 5.1 without considering that, in + * other archs, the user needs to enable NVDIMM support with the + * 'nvdimm' machine option and the default behavior is NVDIMM + * support disabled. It is too late to roll back to the standard + * behavior without breaking 5.1 guests. + */ + if (mc->nvdimm_supported) { + ms->nvdimms_state->is_enabled = true; + } spapr->htab_fd = -1; spapr->use_hotplug_event_source = true; diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 73ee006541..b46c36917c 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -27,10 +27,8 @@ #include "hw/ppc/spapr_nvdimm.h" #include "hw/mem/nvdimm.h" #include "qemu/nvdimm-utils.h" -#include "qemu/option.h" #include "hw/ppc/fdt.h" #include "qemu/range.h" -#include "sysemu/sysemu.h" #include "hw/ppc/spapr_numa.h" bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, @@ -38,7 +36,6 @@ bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, { const MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); const MachineState *ms = MACHINE(hotplug_dev); - const char *nvdimm_opt = qemu_opt_get(qemu_get_machine_opts(), "nvdimm"); g_autofree char *uuidstr = NULL; QemuUUID uuid; int ret; @@ -48,16 +45,7 @@ bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, return false; } - /* - * NVDIMM support went live in 5.1 without considering that, in - * other archs, the user needs to enable NVDIMM support with the - * 'nvdimm' machine option and the default behavior is NVDIMM - * support disabled. It is too late to roll back to the standard - * behavior without breaking 5.1 guests. What we can do is to - * ensure that, if the user sets nvdimm=off, we error out - * regardless of being 5.1 or newer. - */ - if (!ms->nvdimms_state->is_enabled && nvdimm_opt) { + if (!ms->nvdimms_state->is_enabled) { error_setg(errp, "nvdimm device found but 'nvdimm=off' was set"); return false; } diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 7f1bca928c..07fe49da0d 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -152,7 +152,7 @@ static int xilinx_load_device_tree(hwaddr addr, int r; const char *dtb_filename; - dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); + dtb_filename = current_machine->dtb; if (dtb_filename) { fdt = load_device_tree(dtb_filename, &fdt_size); if (!fdt) { diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 2f19a9cda2..e7f6dc5fb3 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -100,14 +100,12 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, int cpu; uint32_t *cells; char *nodename; - const char *dtb_filename; char ethclk_names[] = "pclk\0hclk"; uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1; uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle; - dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); - if (dtb_filename) { - fdt = s->fdt = load_device_tree(dtb_filename, &s->fdt_size); + if (ms->dtb) { + fdt = s->fdt = load_device_tree(ms->dtb, &s->fdt_size); if (!fdt) { error_report("load_device_tree() failed"); exit(1); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 25cea7aa67..3cc18a76e7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -181,7 +181,6 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, { void *fdt; int i, cpu, socket; - const char *dtb_filename; MachineState *mc = MACHINE(s); uint64_t addr, size; uint32_t *clint_cells, *plic_cells; @@ -195,9 +194,8 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; hwaddr flashbase = virt_memmap[VIRT_FLASH].base; - dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); - if (dtb_filename) { - fdt = s->fdt = load_device_tree(dtb_filename, &s->fdt_size); + if (mc->dtb) { + fdt = s->fdt = load_device_tree(mc->dtb, &s->fdt_size); if (!fdt) { error_report("load_device_tree() failed"); exit(1); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index b901e701f0..edb5c3492a 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -170,6 +170,8 @@ static void scsi_dma_restart_bh(void *opaque) scsi_req_unref(req); } aio_context_release(blk_get_aio_context(s->conf.blk)); + /* Drop the reference that was acquired in scsi_dma_restart_cb */ + object_unref(OBJECT(s)); } void scsi_req_retry(SCSIRequest *req) @@ -188,6 +190,8 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state) } if (!s->bh) { AioContext *ctx = blk_get_aio_context(s->conf.blk); + /* The reference is dropped in scsi_dma_restart_bh.*/ + object_ref(OBJECT(s)); s->bh = aio_bh_new(ctx, scsi_dma_restart_bh, s); qemu_bh_schedule(s->bh); } diff --git a/hw/usb/core.c b/hw/usb/core.c index 5234dcc73f..e960036f4d 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -97,7 +97,7 @@ void usb_wakeup(USBEndpoint *ep, unsigned int stream) USBDevice *dev = ep->dev; USBBus *bus = usb_bus_from_device(dev); - if (!qdev_hotplug) { + if (!phase_check(PHASE_MACHINE_READY)) { /* * This is machine init cold plug. No need to wakeup anyone, * all devices will be reset anyway. And trying to wakeup can diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index cea8811295..6b9ef7f6b2 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -930,7 +930,7 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr, * accept it. Having a different masks is possible but the guest will use * sub-optimal block sizes, so warn about it. */ - if (qdev_hotplug) { + if (phase_check(PHASE_MACHINE_READY)) { int new_granule = ctz64(new_mask); int cur_granule = ctz64(cur_mask); diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index b1470b88e6..7be53f1895 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -233,11 +233,10 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine) qemu_irq *extints; DriveInfo *dinfo; PFlashCFI01 *flash = NULL; - QemuOpts *machine_opts = qemu_get_machine_opts(); - const char *kernel_filename = qemu_opt_get(machine_opts, "kernel"); - const char *kernel_cmdline = qemu_opt_get(machine_opts, "append"); - const char *dtb_filename = qemu_opt_get(machine_opts, "dtb"); - const char *initrd_filename = qemu_opt_get(machine_opts, "initrd"); + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *dtb_filename = machine->dtb; + const char *initrd_filename = machine->initrd_filename; const unsigned system_io_size = 224 * MiB; uint32_t freq = 10000000; int n; diff --git a/include/chardev/char.h b/include/chardev/char.h index db42f0a8c6..4181a2784a 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -270,8 +270,7 @@ struct ChardevClass { void (*chr_set_echo)(Chardev *chr, bool echo); void (*chr_set_fe_open)(Chardev *chr, int fe_open); void (*chr_be_event)(Chardev *s, QEMUChrEvent event); - /* Return 0 if succeeded, 1 if failed */ - int (*chr_machine_done)(Chardev *chr); + void (*chr_options_parsed)(Chardev *chr); }; Chardev *qemu_chardev_new(const char *id, const char *typename, @@ -283,6 +282,9 @@ extern int term_escape_char; GSource *qemu_chr_timeout_add_ms(Chardev *chr, guint ms, GSourceFunc func, void *private); +void suspend_mux_open(void); +void resume_mux_open(void); + /* console.c */ void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp); diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index bd5e15dd7d..5a0a2d93e0 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -105,4 +105,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length); #endif +/* vl.c */ +extern int singlestep; + #endif /* CPU_COMMON_H */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 94fe05daaa..fab573da06 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -676,7 +676,4 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu, MemoryRegionSection *section); #endif -/* vl.c */ -extern int singlestep; - #endif diff --git a/include/exec/poison.h b/include/exec/poison.h index 7b9ac361dc..d7ae1f23e7 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -3,7 +3,6 @@ #ifndef HW_POISON_H #define HW_POISON_H -#ifdef __GNUC__ #pragma GCC poison TARGET_I386 #pragma GCC poison TARGET_X86_64 @@ -93,4 +92,3 @@ #pragma GCC poison CONFIG_SOFTMMU #endif -#endif diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 8f91faebc3..bafc311bfa 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -780,12 +780,12 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev); const char *qdev_fw_name(DeviceState *dev); +void qdev_assert_realized_properly(void); Object *qdev_get_machine(void); /* FIXME: make this a link<> */ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp); -extern bool qdev_hotplug; extern bool qdev_hot_removed; char *qdev_get_dev_path(DeviceState *dev); @@ -811,4 +811,35 @@ void device_listener_unregister(DeviceListener *listener); */ bool qdev_should_hide_device(QemuOpts *opts); +typedef enum MachineInitPhase { + /* current_machine is NULL. */ + PHASE_NO_MACHINE, + + /* current_machine is not NULL, but current_machine->accel is NULL. */ + PHASE_MACHINE_CREATED, + + /* + * current_machine->accel is not NULL, but the machine properties have + * not been validated and machine_class->init has not yet been called. + */ + PHASE_ACCEL_CREATED, + + /* + * machine_class->init has been called, thus creating any embedded + * devices and validating machine properties. Devices created at + * this time are considered to be cold-plugged. + */ + PHASE_MACHINE_INITIALIZED, + + /* + * QEMU is ready to start CPUs and devices created at this time + * are considered to be hot-plugged. The monitor is not restricted + * to "preconfig" commands. + */ + PHASE_MACHINE_READY, +} MachineInitPhase; + +extern bool phase_check(MachineInitPhase phase); +extern void phase_advance(MachineInitPhase phase); + #endif diff --git a/include/hw/xen/interface/io/ring.h b/include/hw/xen/interface/io/ring.h index 5d048b335c..115705f3f4 100644 --- a/include/hw/xen/interface/io/ring.h +++ b/include/hw/xen/interface/io/ring.h @@ -206,21 +206,12 @@ typedef struct __name##_back_ring __name##_back_ring_t #define RING_HAS_UNCONSUMED_RESPONSES(_r) \ ((_r)->sring->rsp_prod - (_r)->rsp_cons) -#ifdef __GNUC__ #define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ unsigned int rsp = RING_SIZE(_r) - \ ((_r)->req_cons - (_r)->rsp_prod_pvt); \ req < rsp ? req : rsp; \ }) -#else -/* Same as above, but without the nice GCC ({ ... }) syntax. */ -#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ - ((((_r)->sring->req_prod - (_r)->req_cons) < \ - (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \ - ((_r)->sring->req_prod - (_r)->req_cons) : \ - (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) -#endif /* Direct access to individual ring elements, by index. */ #define RING_GET_REQUEST(_r, _idx) \ diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index af8d96c570..1486cac3ef 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -48,6 +48,7 @@ void qmp_disable_command(QmpCommandList *cmds, const char *name); void qmp_enable_command(QmpCommandList *cmds, const char *name); bool qmp_command_is_enabled(const QmpCommand *cmd); +bool qmp_command_available(const QmpCommand *cmd, Error **errp); const char *qmp_command_name(const QmpCommand *cmd); bool qmp_has_success_response(const QmpCommand *cmd); QDict *qmp_error_response(Error *err); diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index c1d211a351..8f4b3a80fb 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -241,23 +241,6 @@ #else /* __ATOMIC_RELAXED */ -/* - * We use GCC builtin if it's available, as that can use mfence on - * 32-bit as well, e.g. if built with -march=pentium-m. However, on - * i386 the spec is buggy, and the implementation followed it until - * 4.3 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36793). - */ -#if defined(__i386__) || defined(__x86_64__) -#if !QEMU_GNUC_PREREQ(4, 4) -#if defined __x86_64__ -#define smp_mb() ({ asm volatile("mfence" ::: "memory"); (void)0; }) -#else -#define smp_mb() ({ asm volatile("lock; addl $0,0(%%esp) " ::: "memory"); (void)0; }) -#endif -#endif -#endif - - #ifdef __alpha__ #define smp_read_barrier_depends() asm volatile("mb":::"memory") #endif diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index c76281f354..1b9e58e82b 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -11,17 +11,6 @@ #define QEMU_STATIC_ANALYSIS 1 #endif -/*---------------------------------------------------------------------------- -| The macro QEMU_GNUC_PREREQ tests for minimum version of the GNU C compiler. -| The code is a copy of SOFTFLOAT_GNUC_PREREQ, see softfloat-macros.h. -*----------------------------------------------------------------------------*/ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) -# define QEMU_GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -# define QEMU_GNUC_PREREQ(maj, min) 0 -#endif - #define QEMU_NORETURN __attribute__ ((__noreturn__)) #define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) @@ -44,10 +33,6 @@ #endif #ifndef likely -#if __GNUC__ < 3 -#define __builtin_expect(x, n) (x) -#endif - #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #endif @@ -68,14 +53,10 @@ (offsetof(container, field) + sizeof_field(container, field)) /* Convert from a base type to a parent type, with compile time checking. */ -#ifdef __GNUC__ #define DO_UPCAST(type, field, dev) ( __extension__ ( { \ char __attribute__((unused)) offset_must_be_zero[ \ -offsetof(type, field)]; \ container_of(dev, type, field);})) -#else -#define DO_UPCAST(type, field, dev) container_of(dev, type, field) -#endif #define typeof_field(type, field) typeof(((type *)0)->field) #define type_check(t1,t2) ((t1*)0 - (t2*)0) @@ -103,21 +84,19 @@ #define QEMU_BUILD_BUG_ON_ZERO(x) (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - \ sizeof(QEMU_BUILD_BUG_ON_STRUCT(x))) -#if defined __GNUC__ -# if !QEMU_GNUC_PREREQ(4, 4) - /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */ -# define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m))) -# else - /* Use gnu_printf when supported (qemu uses standard format strings). */ -# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m))) -# if defined(_WIN32) - /* Map __printf__ to __gnu_printf__ because we want standard format strings - * even when MinGW or GLib include files use __printf__. */ -# define __printf__ __gnu_printf__ -# endif -# endif +#if defined(__clang__) +/* clang doesn't support gnu_printf, so use printf. */ +# define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m))) #else -#define GCC_FMT_ATTR(n, m) +/* Use gnu_printf (qemu uses standard format strings). */ +# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m))) +# if defined(_WIN32) +/* + * Map __printf__ to __gnu_printf__ because we want standard format strings even + * when MinGW or GLib include files use __printf__. + */ +# define __printf__ __gnu_printf__ +# endif #endif #ifndef __has_warning diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index ab790ad105..841deed79c 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -45,7 +45,7 @@ static inline void qemu_plugin_add_opts(void) } void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head); -int qemu_plugin_load_list(QemuPluginList *head); +int qemu_plugin_load_list(QemuPluginList *head, Error **errp); union qemu_plugin_cb_sig { qemu_plugin_simple_cb_t simple; @@ -199,7 +199,7 @@ static inline void qemu_plugin_opt_parse(const char *optarg, exit(1); } -static inline int qemu_plugin_load_list(QemuPluginList *head) +static inline int qemu_plugin_load_list(QemuPluginList *head, Error **errp) { return 0; } diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index bab8b0d4b3..5775e82c4e 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -28,13 +28,8 @@ #endif #define QEMU_PLUGIN_LOCAL #else - #if __GNUC__ >= 4 - #define QEMU_PLUGIN_EXPORT __attribute__((visibility("default"))) - #define QEMU_PLUGIN_LOCAL __attribute__((visibility("hidden"))) - #else - #define QEMU_PLUGIN_EXPORT - #define QEMU_PLUGIN_LOCAL - #endif + #define QEMU_PLUGIN_EXPORT __attribute__((visibility("default"))) + #define QEMU_PLUGIN_LOCAL __attribute__((visibility("hidden"))) #endif typedef uint64_t qemu_plugin_id_t; diff --git a/include/sysemu/runstate-action.h b/include/sysemu/runstate-action.h new file mode 100644 index 0000000000..cff45a047b --- /dev/null +++ b/include/sysemu/runstate-action.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef RUNSTATE_ACTION_H +#define RUNSTATE_ACTION_H + +#include "qapi/qapi-commands-run-state.h" + +/* in softmmu/runstate-action.c */ +extern RebootAction reboot_action; +extern ShutdownAction shutdown_action; +extern PanicAction panic_action; + +#endif /* RUNSTATE_ACTION_H */ diff --git a/include/sysemu/runstate.h b/include/sysemu/runstate.h index f760094858..e557f470d4 100644 --- a/include/sysemu/runstate.h +++ b/include/sysemu/runstate.h @@ -41,7 +41,6 @@ typedef enum WakeupReason { QEMU_WAKEUP_REASON_OTHER, } WakeupReason; -void qemu_exit_preconfig_request(void); void qemu_system_reset_request(ShutdownCause reason); void qemu_system_suspend_request(void); void qemu_register_suspend_notifier(Notifier *notifier); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 29c32f9851..8fae667172 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -16,14 +16,14 @@ extern bool qemu_uuid_set; void qemu_add_exit_notifier(Notifier *notify); void qemu_remove_exit_notifier(Notifier *notify); -extern bool machine_init_done; - void qemu_run_machine_init_done_notifiers(void); void qemu_add_machine_init_done_notifier(Notifier *notify); void qemu_remove_machine_init_done_notifier(Notifier *notify); void configure_rtc(QemuOpts *opts); +void qemu_init_subsystems(void); + extern int autostart; typedef enum { @@ -43,7 +43,6 @@ extern int win2k_install_hack; extern int alt_grab; extern int ctrl_grab; extern int graphic_rotate; -extern int no_shutdown; extern int old_param; extern int boot_menu; extern bool boot_strict; @@ -103,8 +102,6 @@ typedef void QEMUBootSetHandler(void *opaque, const char *boot_order, void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque); void qemu_boot_set(const char *boot_order, Error **errp); -QemuOpts *qemu_get_machine_opts(void); - bool defaults_enabled(void); void qemu_init(int argc, char **argv, char **envp); diff --git a/linux-user/main.c b/linux-user/main.c index 24d1eb73ad..750a01118f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -671,9 +671,7 @@ int main(int argc, char **argv, char **envp) exit(1); } trace_init_file(); - if (qemu_plugin_load_list(&plugins)) { - exit(1); - } + qemu_plugin_load_list(&plugins, &error_fatal); /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); diff --git a/linux-user/strace.c b/linux-user/strace.c index 11fea14fba..e00275fcb5 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -24,7 +24,6 @@ struct syscallname { abi_long, abi_long, abi_long); }; -#ifdef __GNUC__ /* * It is possible that target doesn't have syscall that uses * following flags but we don't want the compiler to warn @@ -32,9 +31,6 @@ struct syscallname { * functions. It is ok to keep them while not used. */ #define UNUSED __attribute__ ((unused)) -#else -#define UNUSED -#endif /* * Structure used to translate flag values into strings. This is diff --git a/monitor/hmp.c b/monitor/hmp.c index d40f4f4391..6c0b33a0b1 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include <dirent.h> +#include "hw/qdev-core.h" #include "monitor-internal.h" #include "qapi/error.h" #include "qapi/qmp/qdict.h" @@ -215,7 +216,7 @@ static bool cmd_can_preconfig(const HMPCommand *cmd) static bool cmd_available(const HMPCommand *cmd) { - return !runstate_check(RUN_STATE_PRECONFIG) || cmd_can_preconfig(cmd); + return phase_check(PHASE_MACHINE_READY) || cmd_can_preconfig(cmd); } static void help_cmd_dump_one(Monitor *mon, @@ -658,8 +659,8 @@ static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon, return NULL; } if (!cmd_available(cmd)) { - monitor_printf(mon, "Command '%.*s' not available with -preconfig " - "until after exit_preconfig.\n", + monitor_printf(mon, "Command '%.*s' not available " + "until machine initialization has completed.\n", (int)(p - cmdp_start), cmdp_start); return NULL; } diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 6223a28e8b..34f7e75b7b 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -26,6 +26,7 @@ #include "ui/vnc.h" #include "sysemu/kvm.h" #include "sysemu/runstate.h" +#include "sysemu/runstate-action.h" #include "sysemu/arch_init.h" #include "sysemu/blockdev.h" #include "sysemu/block-backend.h" @@ -72,7 +73,7 @@ UuidInfo *qmp_query_uuid(Error **errp) void qmp_quit(Error **errp) { - no_shutdown = 0; + shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT); } @@ -102,16 +103,6 @@ void qmp_system_powerdown(Error **errp) qemu_system_powerdown_request(); } -void qmp_x_exit_preconfig(Error **errp) -{ - if (!runstate_check(RUN_STATE_PRECONFIG)) { - error_setg(errp, "The command is permitted only in '%s' state", - RunState_str(RUN_STATE_PRECONFIG)); - return; - } - qemu_exit_preconfig_request(); -} - void qmp_cont(Error **errp) { BlockBackend *blk; diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index 084fc10f05..30771f8d17 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -41,7 +41,6 @@ override CFLAGS += $(call cc-option, $(Wa)-32) LD_I386_EMULATION ?= elf_i386 override LDFLAGS = -m $(LD_I386_EMULATION) -T $(SRC_DIR)/flat.lds -override LDFLAGS += $(LDFLAGS_NOPIE) all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin diff --git a/plugins/loader.c b/plugins/loader.c index 8ac5dbc20f..5cb9794fda 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -150,7 +150,7 @@ static uint64_t xorshift64star(uint64_t x) return x * UINT64_C(2685821657736338717); } -static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info) +static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info, Error **errp) { qemu_plugin_install_func_t install; struct qemu_plugin_ctx *ctx; @@ -163,37 +163,37 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info) ctx->handle = g_module_open(desc->path, G_MODULE_BIND_LOCAL); if (ctx->handle == NULL) { - error_report("%s: %s", __func__, g_module_error()); + error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error()); goto err_dlopen; } if (!g_module_symbol(ctx->handle, "qemu_plugin_install", &sym)) { - error_report("%s: %s", __func__, g_module_error()); + error_setg(errp, "Could not load plugin %s: %s", desc->path, g_module_error()); goto err_symbol; } install = (qemu_plugin_install_func_t) sym; /* symbol was found; it could be NULL though */ if (install == NULL) { - error_report("%s: %s: qemu_plugin_install is NULL", - __func__, desc->path); + error_setg(errp, "Could not load plugin %s: qemu_plugin_install is NULL", + desc->path); goto err_symbol; } if (!g_module_symbol(ctx->handle, "qemu_plugin_version", &sym)) { - error_report("TCG plugin %s does not declare API version %s", - desc->path, g_module_error()); + error_setg(errp, "Could not load plugin %s: plugin does not declare API version %s", + desc->path, g_module_error()); goto err_symbol; } else { int version = *(int *)sym; if (version < QEMU_PLUGIN_MIN_VERSION) { - error_report("TCG plugin %s requires API version %d, but " - "this QEMU supports only a minimum version of %d", - desc->path, version, QEMU_PLUGIN_MIN_VERSION); + error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but " + "this QEMU supports only a minimum version of %d", + desc->path, version, QEMU_PLUGIN_MIN_VERSION); goto err_symbol; } else if (version > QEMU_PLUGIN_VERSION) { - error_report("TCG plugin %s requires API version %d, but " - "this QEMU supports only up to version %d", - desc->path, version, QEMU_PLUGIN_VERSION); + error_setg(errp, "Could not load plugin %s: plugin requires API version %d, but " + "this QEMU supports only up to version %d", + desc->path, version, QEMU_PLUGIN_VERSION); goto err_symbol; } } @@ -220,8 +220,8 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info) rc = install(ctx->id, info, desc->argc, desc->argv); ctx->installing = false; if (rc) { - error_report("%s: qemu_plugin_install returned error code %d", - __func__, rc); + error_setg(errp, "Could not load plugin %s: qemu_plugin_install returned error code %d", + desc->path, rc); /* * we cannot rely on the plugin doing its own cleanup, so * call a full uninstall if the plugin did not yet call it. @@ -263,7 +263,7 @@ static void plugin_desc_free(struct qemu_plugin_desc *desc) * Note: the descriptor of each successfully installed plugin is removed * from the list given by @head. */ -int qemu_plugin_load_list(QemuPluginList *head) +int qemu_plugin_load_list(QemuPluginList *head, Error **errp) { struct qemu_plugin_desc *desc, *next; g_autofree qemu_info_t *info = g_new0(qemu_info_t, 1); @@ -283,7 +283,7 @@ int qemu_plugin_load_list(QemuPluginList *head) QTAILQ_FOREACH_SAFE(desc, head, entry, next) { int err; - err = plugin_load(desc, info); + err = plugin_load(desc, info, errp); if (err) { return err; } diff --git a/qapi/control.json b/qapi/control.json index 9c8a51352d..2615d5170b 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -219,7 +219,8 @@ # -> { "execute": "quit" } # <- { "return": {} } ## -{ 'command': 'quit' } +{ 'command': 'quit', + 'allow-preconfig': true } ## # @MonitorMode: diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 9a2d7dd29a..0a2b20a4e4 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -167,10 +167,7 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, goto out; } - if (runstate_check(RUN_STATE_PRECONFIG) && - !(cmd->options & QCO_ALLOW_PRECONFIG)) { - error_setg(&err, "The command '%s' isn't permitted in '%s' state", - cmd->name, RunState_str(RUN_STATE_PRECONFIG)); + if (!qmp_command_available(cmd, &err)) { goto out; } diff --git a/qapi/run-state.json b/qapi/run-state.json index b2f77cbf3f..1f3b329f05 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -50,15 +50,12 @@ # @colo: guest is paused to save/restore VM state under colo checkpoint, # VM can not get into this state unless colo capability is enabled # for migration. (since 2.8) -# @preconfig: QEMU is paused before board specific init callback is executed. -# The state is reachable only if the --preconfig CLI option is used. -# (Since 3.0) ## { 'enum': 'RunState', 'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused', 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm', 'running', 'save-vm', 'shutdown', 'suspended', 'watchdog', - 'guest-panicked', 'colo', 'preconfig' ] } + 'guest-panicked', 'colo' ] } ## # @ShutdownCause: @@ -329,6 +326,46 @@ 'inject-nmi' ] } ## +# @RebootAction: +# +# Possible QEMU actions upon guest reboot +# +# @none: Reset the VM +# +# @shutdown: Shutdown the VM and exit +# +# Since: 6.0 +## +{ 'enum': 'RebootAction', + 'data': [ 'none', 'shutdown' ] } + +## +# @ShutdownAction: +# +# Possible QEMU actions upon guest shutdown +# +# @poweroff: Shutdown the VM and exit +# +# @pause: pause the VM# +# +# Since: 6.0 +## +{ 'enum': 'ShutdownAction', + 'data': [ 'poweroff', 'pause' ] } + +## +# @PanicAction: +# +# @none: Continue VM execution +# +# @pause: Pause the VM +# +# Since: 6.0 +## +{ 'enum': 'PanicAction', + 'data': [ 'poweroff', 'pause', 'none' ] } + +## # @watchdog-set-action: # # Set watchdog action @@ -338,6 +375,40 @@ { 'command': 'watchdog-set-action', 'data' : {'action': 'WatchdogAction'} } ## +# @set-action: +# +# Set the actions that will be taken by the emulator in response to guest +# events. +# +# @reboot: @RebootAction action taken on guest reboot. +# +# @shutdown: @ShutdownAction action taken on guest shutdown. +# +# @panic: @PanicAction action taken on guest panic. +# +# @watchdog: @WatchdogAction action taken when watchdog timer expires . +# +# Returns: Nothing on success. +# +# Since: 6.0 +# +# Example: +# +# -> { "execute": "set-action", +# "arguments": { "reboot": "shutdown", +# "shutdown" : "pause", +# "panic": "pause", +# "watchdog": "inject-nmi" } } +# <- { "return": {} } +## +{ 'command': 'set-action', + 'data': { '*reboot': 'RebootAction', + '*shutdown': 'ShutdownAction', + '*panic': 'PanicAction', + '*watchdog': 'WatchdogAction' }, + 'allow-preconfig': true } + +## # @GUEST_PANICKED: # # Emitted when guest OS panic is detected diff --git a/qemu-options.hx b/qemu-options.hx index ae8872d1d6..459c916d3d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3713,17 +3713,6 @@ SRST Do not start CPU at startup (you must type 'c' in the monitor). ERST -DEF("realtime", HAS_ARG, QEMU_OPTION_realtime, - "-realtime [mlock=on|off]\n" - " run qemu with realtime features\n" - " mlock=on|off controls mlock support (default: on)\n", - QEMU_ARCH_ALL) -SRST -``-realtime mlock=on|off`` - Run qemu with realtime features. mlocking qemu and guest memory can - be enabled via ``mlock=on`` (enabled by default). -ERST - DEF("overcommit", HAS_ARG, QEMU_OPTION_overcommit, "-overcommit [mem-lock=on|off][cpu-pm=on|off]\n" " run qemu with overcommit hints\n" @@ -3739,8 +3728,7 @@ SRST Locking qemu and guest memory can be enabled via ``mem-lock=on`` (disabled by default). This works when host memory is not - overcommitted and reduces the worst-case latency for guest. This is - equivalent to ``realtime``. + overcommitted and reduces the worst-case latency for guest. Guest ability to manage power state of host cpus (increasing latency for other processes on the same host cpu, but decreasing latency for @@ -3894,6 +3882,31 @@ SRST changes to the disk image. ERST +DEF("action", HAS_ARG, QEMU_OPTION_action, + "-action reboot=none|shutdown\n" + " action when guest reboots [default=none]\n" + "-action shutdown=poweroff|pause\n" + " action when guest shuts down [default=poweroff]\n" + "-action panic=poweroff|pause|none\n" + " action when guest panics [default=poweroff]\n" + "-action watchdog=reset|shutdown|poweroff|inject-nmi|pause|debug|none\n" + " action when watchdog fires [default=reset]\n", + QEMU_ARCH_ALL) +SRST +``-action event=action`` + The action parameter serves to modify QEMU's default behavior when + certain guest events occur. It provides a generic method for specifying the + same behaviors that are modified by the ``-no-reboot`` and ``-no-shutdown`` + parameters. + + Examples: + + ``-action panic=none`` + ``-action reboot=shutdown,shutdown=pause`` + ``-watchdog i6300esb -action watchdog=pause`` + +ERST + DEF("loadvm", HAS_ARG, QEMU_OPTION_loadvm, \ "-loadvm [tag|id]\n" \ " start right away with a saved state (loadvm in monitor)\n", @@ -4079,21 +4092,6 @@ SRST ERST -DEF("show-cursor", 0, QEMU_OPTION_show_cursor, \ - "-show-cursor show cursor\n", QEMU_ARCH_ALL) -SRST -``-show-cursor`` - Show cursor. -ERST - -DEF("tb-size", HAS_ARG, QEMU_OPTION_tb_size, \ - "-tb-size n set TB size\n", QEMU_ARCH_ALL) -SRST -``-tb-size n`` - Set TCG translation block cache size. Deprecated, use - '\ ``-accel tcg,tb-size=n``\ ' instead. -ERST - DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \ "-incoming tcp:[host]:port[,to=maxport][,ipv4][,ipv6]\n" \ "-incoming rdma:host:port[,ipv4][,ipv6]\n" \ diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h index c6bbc05ba3..20eea6b708 100644 --- a/scripts/cocci-macro-file.h +++ b/scripts/cocci-macro-file.h @@ -19,7 +19,6 @@ */ /* From qemu/compiler.h */ -#define QEMU_GNUC_PREREQ(maj, min) 1 #define QEMU_NORETURN __attribute__ ((__noreturn__)) #define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #define QEMU_SENTINEL __attribute__((sentinel)) diff --git a/scripts/git.orderfile b/scripts/git.orderfile index 3736c1d6af..b32203b710 100644 --- a/scripts/git.orderfile +++ b/scripts/git.orderfile @@ -12,6 +12,7 @@ # Documentation docs/* *.rst +*.rst.inc # build system configure @@ -28,9 +29,11 @@ qga/*.json # headers *.h +*.h.inc # decoding tree specification *.decode # code *.c +*.c.inc diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c index b335dae707..b9a3ddc518 100644 --- a/softmmu/device_tree.c +++ b/softmmu/device_tree.c @@ -526,7 +526,7 @@ int qemu_fdt_add_subnode(void *fdt, const char *name) void qemu_fdt_dumpdtb(void *fdt, int size) { - const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb"); + const char *dumpdtb = current_machine->dumpdtb; if (dumpdtb) { /* Dump the dtb to a file and quit */ diff --git a/softmmu/globals.c b/softmmu/globals.c new file mode 100644 index 0000000000..7d0fc81183 --- /dev/null +++ b/softmmu/globals.c @@ -0,0 +1,72 @@ +/* + * Global variables that (mostly) should not exist + * + * Copyright (c) 2003-2020 QEMU contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "exec/cpu-common.h" +#include "hw/display/vga.h" +#include "hw/i386/pc.h" +#include "hw/i386/x86.h" +#include "hw/loader.h" +#include "hw/xen/xen.h" +#include "net/net.h" +#include "sysemu/cpus.h" +#include "sysemu/sysemu.h" + +enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; +int display_opengl; +const char* keyboard_layout; +bool enable_mlock; +bool enable_cpu_pm; +int nb_nics; +NICInfo nd_table[MAX_NICS]; +int autostart = 1; +int vga_interface_type = VGA_NONE; +Chardev *parallel_hds[MAX_PARALLEL_PORTS]; +int win2k_install_hack; +int singlestep; +int fd_bootchk = 1; +int graphic_rotate; +QEMUOptionRom option_rom[MAX_OPTION_ROMS]; +int nb_option_roms; +int old_param; +const char *qemu_name; +int alt_grab; +int ctrl_grab; +unsigned int nb_prom_envs; +const char *prom_envs[MAX_PROM_ENVS]; +int boot_menu; +bool boot_strict; +uint8_t *boot_splash_filedata; +int only_migratable; /* turn it off unless user states otherwise */ +int icount_align_option; + +/* The bytes in qemu_uuid are in the order specified by RFC4122, _not_ in the + * little-endian "wire format" described in the SMBIOS 2.6 specification. + */ +QemuUUID qemu_uuid; +bool qemu_uuid_set; + +uint32_t xen_domid; +enum xen_mode xen_mode = XEN_EMULATE; +bool xen_domid_restrict; diff --git a/softmmu/memory.c b/softmmu/memory.c index 22bacbbc78..333e1ed7b0 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -1548,7 +1548,6 @@ void memory_region_init_ram_shared_nomigrate(MemoryRegion *mr, mr->terminates = true; mr->destructor = memory_region_destructor_ram; mr->ram_block = qemu_ram_alloc(size, share, mr, &err); - mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; if (err) { mr->size = int128_zero(); object_unparent(OBJECT(mr)); @@ -1573,7 +1572,6 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, mr->destructor = memory_region_destructor_ram; mr->ram_block = qemu_ram_alloc_resizeable(size, max_size, resized, mr, &err); - mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; if (err) { mr->size = int128_zero(); object_unparent(OBJECT(mr)); @@ -1598,7 +1596,6 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, mr->destructor = memory_region_destructor_ram; mr->align = align; mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path, &err); - mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; if (err) { mr->size = int128_zero(); object_unparent(OBJECT(mr)); @@ -1622,7 +1619,6 @@ void memory_region_init_ram_from_fd(MemoryRegion *mr, mr->ram_block = qemu_ram_alloc_from_fd(size, mr, share ? RAM_SHARED : 0, fd, &err); - mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; if (err) { mr->size = int128_zero(); object_unparent(OBJECT(mr)); @@ -1641,7 +1637,6 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, mr->ram = true; mr->terminates = true; mr->destructor = memory_region_destructor_ram; - mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; /* qemu_ram_alloc_from_ptr cannot fail with ptr != NULL. */ assert(ptr != NULL); @@ -1661,7 +1656,7 @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr, mr->ops = &ram_device_mem_ops; mr->opaque = mr; mr->destructor = memory_region_destructor_ram; - mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; + /* qemu_ram_alloc_from_ptr cannot fail with ptr != NULL. */ assert(ptr != NULL); mr->ram_block = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_fatal); @@ -1819,6 +1814,11 @@ uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) memory_region_is_iommu(mr))) { mask |= (1 << DIRTY_MEMORY_MIGRATION); } + + if (tcg_enabled() && rb) { + /* TCG only cares about dirty memory logging for RAM, not IOMMU. */ + mask |= (1 << DIRTY_MEMORY_CODE); + } return mask; } diff --git a/softmmu/meson.build b/softmmu/meson.build index d098d89653..2dab6c7eb6 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -4,14 +4,17 @@ specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files( 'cpus.c', 'cpu-throttle.c', 'datadir.c', + 'globals.c', 'physmem.c', 'ioport.c', 'rtc.c', + 'runstate.c', 'memory.c', 'memory_mapping.c', 'qtest.c', 'vl.c', 'cpu-timers.c', + 'runstate-action.c', )]) specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: [files( diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 3027747c03..2cd1de4a2c 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -3255,6 +3255,7 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, AddressSpaceDispatch *d; hwaddr l; MemoryRegion *mr; + Int128 diff; assert(len > 0); @@ -3263,6 +3264,15 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, d = flatview_to_dispatch(cache->fv); cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true); + /* + * cache->xlat is now relative to cache->mrs.mr, not to the section itself. + * Take that into account to compute how many bytes are there between + * cache->xlat and the end of the section. + */ + diff = int128_sub(cache->mrs.size, + int128_make64(cache->xlat - cache->mrs.offset_within_region)); + l = int128_get64(int128_min(diff, int128_make64(l))); + mr = cache->mrs.mr; memory_region_ref(mr); if (memory_access_is_direct(mr, is_write)) { diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index 8c072e3efc..2c57e36c9a 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -25,6 +25,7 @@ #include "sysemu/arch_init.h" #include "qapi/error.h" #include "qapi/qapi-commands-qdev.h" +#include "qapi/qmp/dispatch.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qemu/config-file.h" @@ -244,7 +245,7 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp) dc = DEVICE_CLASS(oc); if (!dc->user_creatable || - (qdev_hotplug && !dc->hotpluggable)) { + (phase_check(PHASE_MACHINE_READY) && !dc->hotpluggable)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", "a pluggable device type"); return NULL; @@ -626,7 +627,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) } } - if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) { + if (phase_check(PHASE_MACHINE_READY) && bus && !qbus_is_hotpluggable(bus)) { error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); return NULL; } @@ -640,15 +641,17 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) dev = qdev_new(driver); /* Check whether the hotplug is allowed by the machine */ - if (qdev_hotplug && !qdev_hotplug_allowed(dev, errp)) { - goto err_del_dev; - } + if (phase_check(PHASE_MACHINE_READY)) { + if (!qdev_hotplug_allowed(dev, errp)) { + goto err_del_dev; + } - if (!bus && qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) { - /* No bus, no machine hotplug handler --> device is not hotpluggable */ - error_setg(errp, "Device '%s' can not be hotplugged on this machine", - driver); - goto err_del_dev; + if (!bus && !qdev_get_machine_hotplug_handler(dev)) { + /* No bus, no machine hotplug handler --> device is not hotpluggable */ + error_setg(errp, "Device '%s' can not be hotplugged on this machine", + driver); + goto err_del_dev; + } } qdev_set_id(dev, qemu_opts_id(opts)); @@ -983,3 +986,14 @@ int qemu_global_option(const char *str) return 0; } + +bool qmp_command_available(const QmpCommand *cmd, Error **errp) +{ + if (!phase_check(PHASE_MACHINE_READY) && + !(cmd->options & QCO_ALLOW_PRECONFIG)) { + error_setg(errp, "The command '%s' is permitted only after machine initialization has completed", + cmd->name); + return false; + } + return true; +} diff --git a/softmmu/runstate-action.c b/softmmu/runstate-action.c new file mode 100644 index 0000000000..99ce880886 --- /dev/null +++ b/softmmu/runstate-action.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "sysemu/runstate-action.h" +#include "sysemu/watchdog.h" +#include "qemu/config-file.h" +#include "qapi/error.h" +#include "qemu/option_int.h" + +RebootAction reboot_action = REBOOT_ACTION_NONE; +ShutdownAction shutdown_action = SHUTDOWN_ACTION_POWEROFF; +PanicAction panic_action = PANIC_ACTION_POWEROFF; + +/* + * Receives actions to be applied for specific guest events + * and sets the internal state as requested. + */ +void qmp_set_action(bool has_reboot, RebootAction reboot, + bool has_shutdown, ShutdownAction shutdown, + bool has_panic, PanicAction panic, + bool has_watchdog, WatchdogAction watchdog, + Error **errp) +{ + if (has_reboot) { + reboot_action = reboot; + } + + if (has_panic) { + panic_action = panic; + } + + if (has_watchdog) { + qmp_watchdog_set_action(watchdog, errp); + } + + /* Process shutdown last, in case the panic action needs to be altered */ + if (has_shutdown) { + shutdown_action = shutdown; + } +} diff --git a/softmmu/runstate.c b/softmmu/runstate.c new file mode 100644 index 0000000000..636aab0add --- /dev/null +++ b/softmmu/runstate.c @@ -0,0 +1,812 @@ +/* + * QEMU main system emulation loop + * + * Copyright (c) 2003-2020 QEMU contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "audio/audio.h" +#include "block/block.h" +#include "chardev/char.h" +#include "crypto/cipher.h" +#include "crypto/init.h" +#include "exec/cpu-common.h" +#include "exec/exec-all.h" +#include "exec/gdbstub.h" +#include "hw/boards.h" +#include "migration/misc.h" +#include "migration/postcopy-ram.h" +#include "monitor/monitor.h" +#include "net/net.h" +#include "net/vhost_net.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-run-state.h" +#include "qapi/qapi-events-run-state.h" +#include "qemu-common.h" +#include "qemu/error-report.h" +#include "qemu/job.h" +#include "qemu/module.h" +#include "qemu/plugin.h" +#include "qemu/sockets.h" +#include "qemu/thread.h" +#include "qom/object.h" +#include "qom/object_interfaces.h" +#include "sysemu/cpus.h" +#include "sysemu/qtest.h" +#include "sysemu/replay.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" +#include "sysemu/runstate-action.h" +#include "sysemu/sysemu.h" +#include "sysemu/tpm.h" +#include "trace.h" + +static NotifierList exit_notifiers = + NOTIFIER_LIST_INITIALIZER(exit_notifiers); + +static RunState current_run_state = RUN_STATE_PRELAUNCH; + +/* We use RUN_STATE__MAX but any invalid value will do */ +static RunState vmstop_requested = RUN_STATE__MAX; +static QemuMutex vmstop_lock; + +typedef struct { + RunState from; + RunState to; +} RunStateTransition; + +static const RunStateTransition runstate_transitions_def[] = { + { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE }, + + { RUN_STATE_DEBUG, RUN_STATE_RUNNING }, + { RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_DEBUG, RUN_STATE_PRELAUNCH }, + + { RUN_STATE_INMIGRATE, RUN_STATE_INTERNAL_ERROR }, + { RUN_STATE_INMIGRATE, RUN_STATE_IO_ERROR }, + { RUN_STATE_INMIGRATE, RUN_STATE_PAUSED }, + { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING }, + { RUN_STATE_INMIGRATE, RUN_STATE_SHUTDOWN }, + { RUN_STATE_INMIGRATE, RUN_STATE_SUSPENDED }, + { RUN_STATE_INMIGRATE, RUN_STATE_WATCHDOG }, + { RUN_STATE_INMIGRATE, RUN_STATE_GUEST_PANICKED }, + { RUN_STATE_INMIGRATE, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH }, + { RUN_STATE_INMIGRATE, RUN_STATE_POSTMIGRATE }, + { RUN_STATE_INMIGRATE, RUN_STATE_COLO }, + + { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED }, + { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PRELAUNCH }, + + { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING }, + { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_IO_ERROR, RUN_STATE_PRELAUNCH }, + + { RUN_STATE_PAUSED, RUN_STATE_RUNNING }, + { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_PAUSED, RUN_STATE_POSTMIGRATE }, + { RUN_STATE_PAUSED, RUN_STATE_PRELAUNCH }, + { RUN_STATE_PAUSED, RUN_STATE_COLO}, + + { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING }, + { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_POSTMIGRATE, RUN_STATE_PRELAUNCH }, + + { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING }, + { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE }, + + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_PAUSED }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_PRELAUNCH }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_COLO}, + + { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING }, + { RUN_STATE_RESTORE_VM, RUN_STATE_PRELAUNCH }, + + { RUN_STATE_COLO, RUN_STATE_RUNNING }, + + { RUN_STATE_RUNNING, RUN_STATE_DEBUG }, + { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR }, + { RUN_STATE_RUNNING, RUN_STATE_IO_ERROR }, + { RUN_STATE_RUNNING, RUN_STATE_PAUSED }, + { RUN_STATE_RUNNING, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_RUNNING, RUN_STATE_RESTORE_VM }, + { RUN_STATE_RUNNING, RUN_STATE_SAVE_VM }, + { RUN_STATE_RUNNING, RUN_STATE_SHUTDOWN }, + { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG }, + { RUN_STATE_RUNNING, RUN_STATE_GUEST_PANICKED }, + { RUN_STATE_RUNNING, RUN_STATE_COLO}, + + { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING }, + + { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED }, + { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_SHUTDOWN, RUN_STATE_PRELAUNCH }, + { RUN_STATE_SHUTDOWN, RUN_STATE_COLO }, + + { RUN_STATE_DEBUG, RUN_STATE_SUSPENDED }, + { RUN_STATE_RUNNING, RUN_STATE_SUSPENDED }, + { RUN_STATE_SUSPENDED, RUN_STATE_RUNNING }, + { RUN_STATE_SUSPENDED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_SUSPENDED, RUN_STATE_PRELAUNCH }, + { RUN_STATE_SUSPENDED, RUN_STATE_COLO}, + + { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING }, + { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_WATCHDOG, RUN_STATE_PRELAUNCH }, + { RUN_STATE_WATCHDOG, RUN_STATE_COLO}, + + { RUN_STATE_GUEST_PANICKED, RUN_STATE_RUNNING }, + { RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_GUEST_PANICKED, RUN_STATE_PRELAUNCH }, + + { RUN_STATE__MAX, RUN_STATE__MAX }, +}; + +static bool runstate_valid_transitions[RUN_STATE__MAX][RUN_STATE__MAX]; + +bool runstate_check(RunState state) +{ + return current_run_state == state; +} + +bool runstate_store(char *str, size_t size) +{ + const char *state = RunState_str(current_run_state); + size_t len = strlen(state) + 1; + + if (len > size) { + return false; + } + memcpy(str, state, len); + return true; +} + +static void runstate_init(void) +{ + const RunStateTransition *p; + + memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions)); + for (p = &runstate_transitions_def[0]; p->from != RUN_STATE__MAX; p++) { + runstate_valid_transitions[p->from][p->to] = true; + } + + qemu_mutex_init(&vmstop_lock); +} + +/* This function will abort() on invalid state transitions */ +void runstate_set(RunState new_state) +{ + assert(new_state < RUN_STATE__MAX); + + trace_runstate_set(current_run_state, RunState_str(current_run_state), + new_state, RunState_str(new_state)); + + if (current_run_state == new_state) { + return; + } + + if (!runstate_valid_transitions[current_run_state][new_state]) { + error_report("invalid runstate transition: '%s' -> '%s'", + RunState_str(current_run_state), + RunState_str(new_state)); + abort(); + } + + current_run_state = new_state; +} + +int runstate_is_running(void) +{ + return runstate_check(RUN_STATE_RUNNING); +} + +bool runstate_needs_reset(void) +{ + return runstate_check(RUN_STATE_INTERNAL_ERROR) || + runstate_check(RUN_STATE_SHUTDOWN); +} + +StatusInfo *qmp_query_status(Error **errp) +{ + StatusInfo *info = g_malloc0(sizeof(*info)); + + info->running = runstate_is_running(); + info->singlestep = singlestep; + info->status = current_run_state; + + return info; +} + +bool qemu_vmstop_requested(RunState *r) +{ + qemu_mutex_lock(&vmstop_lock); + *r = vmstop_requested; + vmstop_requested = RUN_STATE__MAX; + qemu_mutex_unlock(&vmstop_lock); + return *r < RUN_STATE__MAX; +} + +void qemu_system_vmstop_request_prepare(void) +{ + qemu_mutex_lock(&vmstop_lock); +} + +void qemu_system_vmstop_request(RunState state) +{ + vmstop_requested = state; + qemu_mutex_unlock(&vmstop_lock); + qemu_notify_event(); +} +struct VMChangeStateEntry { + VMChangeStateHandler *cb; + void *opaque; + QTAILQ_ENTRY(VMChangeStateEntry) entries; + int priority; +}; + +static QTAILQ_HEAD(, VMChangeStateEntry) vm_change_state_head = + QTAILQ_HEAD_INITIALIZER(vm_change_state_head); + +/** + * qemu_add_vm_change_state_handler_prio: + * @cb: the callback to invoke + * @opaque: user data passed to the callback + * @priority: low priorities execute first when the vm runs and the reverse is + * true when the vm stops + * + * Register a callback function that is invoked when the vm starts or stops + * running. + * + * Returns: an entry to be freed using qemu_del_vm_change_state_handler() + */ +VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( + VMChangeStateHandler *cb, void *opaque, int priority) +{ + VMChangeStateEntry *e; + VMChangeStateEntry *other; + + e = g_malloc0(sizeof(*e)); + e->cb = cb; + e->opaque = opaque; + e->priority = priority; + + /* Keep list sorted in ascending priority order */ + QTAILQ_FOREACH(other, &vm_change_state_head, entries) { + if (priority < other->priority) { + QTAILQ_INSERT_BEFORE(other, e, entries); + return e; + } + } + + QTAILQ_INSERT_TAIL(&vm_change_state_head, e, entries); + return e; +} + +VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, + void *opaque) +{ + return qemu_add_vm_change_state_handler_prio(cb, opaque, 0); +} + +void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) +{ + QTAILQ_REMOVE(&vm_change_state_head, e, entries); + g_free(e); +} + +void vm_state_notify(int running, RunState state) +{ + VMChangeStateEntry *e, *next; + + trace_vm_state_notify(running, state, RunState_str(state)); + + if (running) { + QTAILQ_FOREACH_SAFE(e, &vm_change_state_head, entries, next) { + e->cb(e->opaque, running, state); + } + } else { + QTAILQ_FOREACH_REVERSE_SAFE(e, &vm_change_state_head, entries, next) { + e->cb(e->opaque, running, state); + } + } +} + +static ShutdownCause reset_requested; +static ShutdownCause shutdown_requested; +static int shutdown_signal; +static pid_t shutdown_pid; +static int powerdown_requested; +static int debug_requested; +static int suspend_requested; +static WakeupReason wakeup_reason; +static NotifierList powerdown_notifiers = + NOTIFIER_LIST_INITIALIZER(powerdown_notifiers); +static NotifierList suspend_notifiers = + NOTIFIER_LIST_INITIALIZER(suspend_notifiers); +static NotifierList wakeup_notifiers = + NOTIFIER_LIST_INITIALIZER(wakeup_notifiers); +static NotifierList shutdown_notifiers = + NOTIFIER_LIST_INITIALIZER(shutdown_notifiers); +static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE); + +ShutdownCause qemu_shutdown_requested_get(void) +{ + return shutdown_requested; +} + +ShutdownCause qemu_reset_requested_get(void) +{ + return reset_requested; +} + +static int qemu_shutdown_requested(void) +{ + return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE); +} + +static void qemu_kill_report(void) +{ + if (!qtest_driver() && shutdown_signal) { + if (shutdown_pid == 0) { + /* This happens for eg ^C at the terminal, so it's worth + * avoiding printing an odd message in that case. + */ + error_report("terminating on signal %d", shutdown_signal); + } else { + char *shutdown_cmd = qemu_get_pid_name(shutdown_pid); + + error_report("terminating on signal %d from pid " FMT_pid " (%s)", + shutdown_signal, shutdown_pid, + shutdown_cmd ? shutdown_cmd : "<unknown process>"); + g_free(shutdown_cmd); + } + shutdown_signal = 0; + } +} + +static ShutdownCause qemu_reset_requested(void) +{ + ShutdownCause r = reset_requested; + + if (r && replay_checkpoint(CHECKPOINT_RESET_REQUESTED)) { + reset_requested = SHUTDOWN_CAUSE_NONE; + return r; + } + return SHUTDOWN_CAUSE_NONE; +} + +static int qemu_suspend_requested(void) +{ + int r = suspend_requested; + if (r && replay_checkpoint(CHECKPOINT_SUSPEND_REQUESTED)) { + suspend_requested = 0; + return r; + } + return false; +} + +static WakeupReason qemu_wakeup_requested(void) +{ + return wakeup_reason; +} + +static int qemu_powerdown_requested(void) +{ + int r = powerdown_requested; + powerdown_requested = 0; + return r; +} + +static int qemu_debug_requested(void) +{ + int r = debug_requested; + debug_requested = 0; + return r; +} + +/* + * Reset the VM. Issue an event unless @reason is SHUTDOWN_CAUSE_NONE. + */ +void qemu_system_reset(ShutdownCause reason) +{ + MachineClass *mc; + + mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + + cpu_synchronize_all_states(); + + if (mc && mc->reset) { + mc->reset(current_machine); + } else { + qemu_devices_reset(); + } + if (reason && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { + qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); + } + cpu_synchronize_all_post_reset(); +} + +/* + * Wake the VM after suspend. + */ +static void qemu_system_wakeup(void) +{ + MachineClass *mc; + + mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + + if (mc && mc->wakeup) { + mc->wakeup(current_machine); + } +} + +void qemu_system_guest_panicked(GuestPanicInformation *info) +{ + qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed"); + + if (current_cpu) { + current_cpu->crash_occurred = true; + } + /* + * TODO: Currently the available panic actions are: none, pause, and + * poweroff, but in principle debug and reset could be supported as well. + * Investigate any potential use cases for the unimplemented actions. + */ + if (panic_action == PANIC_ACTION_PAUSE) { + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, + !!info, info); + vm_stop(RUN_STATE_GUEST_PANICKED); + } else if (panic_action == PANIC_ACTION_POWEROFF) { + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_POWEROFF, + !!info, info); + vm_stop(RUN_STATE_GUEST_PANICKED); + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC); + } else { + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_RUN, + !!info, info); + } + + if (info) { + if (info->type == GUEST_PANIC_INFORMATION_TYPE_HYPER_V) { + qemu_log_mask(LOG_GUEST_ERROR, "\nHV crash parameters: (%#"PRIx64 + " %#"PRIx64" %#"PRIx64" %#"PRIx64" %#"PRIx64")\n", + info->u.hyper_v.arg1, + info->u.hyper_v.arg2, + info->u.hyper_v.arg3, + info->u.hyper_v.arg4, + info->u.hyper_v.arg5); + } else if (info->type == GUEST_PANIC_INFORMATION_TYPE_S390) { + qemu_log_mask(LOG_GUEST_ERROR, " on cpu %d: %s\n" + "PSW: 0x%016" PRIx64 " 0x%016" PRIx64"\n", + info->u.s390.core, + S390CrashReason_str(info->u.s390.reason), + info->u.s390.psw_mask, + info->u.s390.psw_addr); + } + qapi_free_GuestPanicInformation(info); + } +} + +void qemu_system_guest_crashloaded(GuestPanicInformation *info) +{ + qemu_log_mask(LOG_GUEST_ERROR, "Guest crash loaded"); + + qapi_event_send_guest_crashloaded(GUEST_PANIC_ACTION_RUN, + !!info, info); + + if (info) { + qapi_free_GuestPanicInformation(info); + } +} + +void qemu_system_reset_request(ShutdownCause reason) +{ + if (reboot_action == REBOOT_ACTION_SHUTDOWN && + reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { + shutdown_requested = reason; + } else { + reset_requested = reason; + } + cpu_stop_current(); + qemu_notify_event(); +} + +static void qemu_system_suspend(void) +{ + pause_all_vcpus(); + notifier_list_notify(&suspend_notifiers, NULL); + runstate_set(RUN_STATE_SUSPENDED); + qapi_event_send_suspend(); +} + +void qemu_system_suspend_request(void) +{ + if (runstate_check(RUN_STATE_SUSPENDED)) { + return; + } + suspend_requested = 1; + cpu_stop_current(); + qemu_notify_event(); +} + +void qemu_register_suspend_notifier(Notifier *notifier) +{ + notifier_list_add(&suspend_notifiers, notifier); +} + +void qemu_system_wakeup_request(WakeupReason reason, Error **errp) +{ + trace_system_wakeup_request(reason); + + if (!runstate_check(RUN_STATE_SUSPENDED)) { + error_setg(errp, + "Unable to wake up: guest is not in suspended state"); + return; + } + if (!(wakeup_reason_mask & (1 << reason))) { + return; + } + runstate_set(RUN_STATE_RUNNING); + wakeup_reason = reason; + qemu_notify_event(); +} + +void qemu_system_wakeup_enable(WakeupReason reason, bool enabled) +{ + if (enabled) { + wakeup_reason_mask |= (1 << reason); + } else { + wakeup_reason_mask &= ~(1 << reason); + } +} + +void qemu_register_wakeup_notifier(Notifier *notifier) +{ + notifier_list_add(&wakeup_notifiers, notifier); +} + +static bool wakeup_suspend_enabled; + +void qemu_register_wakeup_support(void) +{ + wakeup_suspend_enabled = true; +} + +bool qemu_wakeup_suspend_enabled(void) +{ + return wakeup_suspend_enabled; +} + +void qemu_system_killed(int signal, pid_t pid) +{ + shutdown_signal = signal; + shutdown_pid = pid; + shutdown_action = SHUTDOWN_ACTION_POWEROFF; + + /* Cannot call qemu_system_shutdown_request directly because + * we are in a signal handler. + */ + shutdown_requested = SHUTDOWN_CAUSE_HOST_SIGNAL; + qemu_notify_event(); +} + +void qemu_system_shutdown_request(ShutdownCause reason) +{ + trace_qemu_system_shutdown_request(reason); + replay_shutdown_request(reason); + shutdown_requested = reason; + qemu_notify_event(); +} + +static void qemu_system_powerdown(void) +{ + qapi_event_send_powerdown(); + notifier_list_notify(&powerdown_notifiers, NULL); +} + +static void qemu_system_shutdown(ShutdownCause cause) +{ + qapi_event_send_shutdown(shutdown_caused_by_guest(cause), cause); + notifier_list_notify(&shutdown_notifiers, &cause); +} + +void qemu_system_powerdown_request(void) +{ + trace_qemu_system_powerdown_request(); + powerdown_requested = 1; + qemu_notify_event(); +} + +void qemu_register_powerdown_notifier(Notifier *notifier) +{ + notifier_list_add(&powerdown_notifiers, notifier); +} + +void qemu_register_shutdown_notifier(Notifier *notifier) +{ + notifier_list_add(&shutdown_notifiers, notifier); +} + +void qemu_system_debug_request(void) +{ + debug_requested = 1; + qemu_notify_event(); +} + +static bool main_loop_should_exit(void) +{ + RunState r; + ShutdownCause request; + + if (qemu_debug_requested()) { + vm_stop(RUN_STATE_DEBUG); + } + if (qemu_suspend_requested()) { + qemu_system_suspend(); + } + request = qemu_shutdown_requested(); + if (request) { + qemu_kill_report(); + qemu_system_shutdown(request); + if (shutdown_action == SHUTDOWN_ACTION_PAUSE) { + vm_stop(RUN_STATE_SHUTDOWN); + } else { + return true; + } + } + request = qemu_reset_requested(); + if (request) { + pause_all_vcpus(); + qemu_system_reset(request); + resume_all_vcpus(); + /* + * runstate can change in pause_all_vcpus() + * as iothread mutex is unlocked + */ + if (!runstate_check(RUN_STATE_RUNNING) && + !runstate_check(RUN_STATE_INMIGRATE) && + !runstate_check(RUN_STATE_FINISH_MIGRATE)) { + runstate_set(RUN_STATE_PRELAUNCH); + } + } + if (qemu_wakeup_requested()) { + pause_all_vcpus(); + qemu_system_wakeup(); + notifier_list_notify(&wakeup_notifiers, &wakeup_reason); + wakeup_reason = QEMU_WAKEUP_REASON_NONE; + resume_all_vcpus(); + qapi_event_send_wakeup(); + } + if (qemu_powerdown_requested()) { + qemu_system_powerdown(); + } + if (qemu_vmstop_requested(&r)) { + vm_stop(r); + } + return false; +} + +void qemu_main_loop(void) +{ +#ifdef CONFIG_PROFILER + int64_t ti; +#endif + while (!main_loop_should_exit()) { +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif + main_loop_wait(false); +#ifdef CONFIG_PROFILER + dev_time += profile_getclock() - ti; +#endif + } +} + +void qemu_add_exit_notifier(Notifier *notify) +{ + notifier_list_add(&exit_notifiers, notify); +} + +void qemu_remove_exit_notifier(Notifier *notify) +{ + notifier_remove(notify); +} + +static void qemu_run_exit_notifiers(void) +{ + notifier_list_notify(&exit_notifiers, NULL); +} + +void qemu_init_subsystems(void) +{ + Error *err; + + os_set_line_buffering(); + + module_call_init(MODULE_INIT_TRACE); + + qemu_init_cpu_list(); + qemu_init_cpu_loop(); + qemu_mutex_lock_iothread(); + + atexit(qemu_run_exit_notifiers); + + module_call_init(MODULE_INIT_QOM); + module_call_init(MODULE_INIT_MIGRATION); + + runstate_init(); + precopy_infrastructure_init(); + postcopy_infrastructure_init(); + monitor_init_globals(); + + if (qcrypto_init(&err) < 0) { + error_reportf_err(err, "cannot initialize crypto: "); + exit(1); + } + + os_setup_early_signal_handling(); + + bdrv_init_with_whitelist(); + socket_init(); +} + + +void qemu_cleanup(void) +{ + gdbserver_cleanup(); + + /* + * cleaning up the migration object cancels any existing migration + * try to do this early so that it also stops using devices. + */ + migration_shutdown(); + + /* + * We must cancel all block jobs while the block layer is drained, + * or cancelling will be affected by throttling and thus may block + * for an extended period of time. + * vm_shutdown() will bdrv_drain_all(), so we may as well include + * it in the drained section. + * We do not need to end this section, because we do not want any + * requests happening from here on anyway. + */ + bdrv_drain_all_begin(); + + /* No more vcpu or device emulation activity beyond this point */ + vm_shutdown(); + replay_finish(); + + job_cancel_sync_all(); + bdrv_close_all(); + + /* vhost-user must be cleaned up before chardevs. */ + tpm_cleanup(); + net_cleanup(); + audio_cleanup(); + monitor_cleanup(); + qemu_chr_cleanup(); + user_creatable_cleanup(); + /* TODO: unref root container, check all devices are ok */ +} diff --git a/softmmu/vl.c b/softmmu/vl.c index cbf3896ce6..0ed5c5ba93 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -26,15 +26,18 @@ #include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" +#include "exec/cpu-common.h" #include "hw/boards.h" #include "hw/qdev-properties.h" #include "qapi/error.h" +#include "qapi/qmp/qdict.h" #include "qemu-version.h" #include "qemu/cutils.h" #include "qemu/help_option.h" #include "qemu/uuid.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" +#include "sysemu/runstate-action.h" #include "sysemu/seccomp.h" #include "sysemu/tcg.h" #include "sysemu/xen.h" @@ -67,9 +70,10 @@ #include "qemu/log.h" #include "sysemu/blockdev.h" #include "hw/block/block.h" +#include "hw/i386/x86.h" +#include "hw/i386/pc.h" #include "migration/misc.h" #include "migration/snapshot.h" -#include "migration/global_state.h" #include "sysemu/tpm.h" #include "sysemu/dma.h" #include "hw/audio/soundhw.h" @@ -112,7 +116,6 @@ #include "qapi/qapi-commands-block-core.h" #include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-misc.h" -#include "qapi/qapi-commands-run-state.h" #include "qapi/qapi-commands-ui.h" #include "qapi/qmp/qerror.h" #include "sysemu/iothread.h" @@ -140,17 +143,8 @@ static bool preconfig_requested; static QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list); static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); static bool nographic = false; -enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; static int mem_prealloc; /* force preallocation of physical target memory */ -int display_opengl; -const char* keyboard_layout = NULL; static ram_addr_t ram_size; -bool enable_mlock = false; -bool enable_cpu_pm = false; -int nb_nics; -NICInfo nd_table[MAX_NICS]; -int autostart = 1; -int vga_interface_type = VGA_NONE; static const char *vga_model = NULL; static DisplayOptions dpy; static int num_serial_hds; @@ -158,44 +152,10 @@ static Chardev **serial_hds; static const char *log_mask; static const char *log_file; static bool list_data_dirs; -Chardev *parallel_hds[MAX_PARALLEL_PORTS]; -int win2k_install_hack = 0; -int singlestep = 0; -int fd_bootchk = 1; -static int no_reboot; -int no_shutdown = 0; -int graphic_rotate = 0; static const char *watchdog; -QEMUOptionRom option_rom[MAX_OPTION_ROMS]; -int nb_option_roms; -int old_param = 0; -const char *qemu_name; -int alt_grab = 0; -int ctrl_grab = 0; -unsigned int nb_prom_envs = 0; -const char *prom_envs[MAX_PROM_ENVS]; -int boot_menu; -bool boot_strict; -uint8_t *boot_splash_filedata; -int only_migratable; /* turn it off unless user states otherwise */ -bool wakeup_suspend_enabled; -int icount_align_option; static const char *qtest_chrdev; static const char *qtest_log; -/* The bytes in qemu_uuid are in the order specified by RFC4122, _not_ in the - * little-endian "wire format" described in the SMBIOS 2.6 specification. - */ -QemuUUID qemu_uuid; -bool qemu_uuid_set; - -static NotifierList exit_notifiers = - NOTIFIER_LIST_INITIALIZER(exit_notifiers); - -uint32_t xen_domid; -enum xen_mode xen_mode = XEN_EMULATE; -bool xen_domid_restrict; - static int has_defaults = 1; static int default_serial = 1; static int default_parallel = 1; @@ -366,18 +326,6 @@ static QemuOptsList qemu_tpmdev_opts = { }, }; -static QemuOptsList qemu_realtime_opts = { - .name = "realtime", - .head = QTAILQ_HEAD_INITIALIZER(qemu_realtime_opts.head), - .desc = { - { - .name = "mlock", - .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - static QemuOptsList qemu_overcommit_opts = { .name = "overcommit", .head = QTAILQ_HEAD_INITIALIZER(qemu_overcommit_opts.head), @@ -518,12 +466,34 @@ static QemuOptsList qemu_fw_cfg_opts = { }, }; +static QemuOptsList qemu_action_opts = { + .name = "action", + .merge_lists = true, + .head = QTAILQ_HEAD_INITIALIZER(qemu_action_opts.head), + .desc = { + { + .name = "shutdown", + .type = QEMU_OPT_STRING, + },{ + .name = "reboot", + .type = QEMU_OPT_STRING, + },{ + .name = "panic", + .type = QEMU_OPT_STRING, + },{ + .name = "watchdog", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + /** * Get machine options * * Returns: machine options (never null). */ -QemuOpts *qemu_get_machine_opts(void) +static QemuOpts *qemu_get_machine_opts(void) { return qemu_find_opts_singleton("machine"); } @@ -533,12 +503,6 @@ const char *qemu_get_vm_name(void) return qemu_name; } -static void res_free(void) -{ - g_free(boot_splash_filedata); - boot_splash_filedata = NULL; -} - static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp) { const char *driver = qemu_opt_get(opts, "driver"); @@ -554,212 +518,6 @@ static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp) return 0; } -/***********************************************************/ -/* QEMU state */ - -static RunState current_run_state = RUN_STATE_PRECONFIG; - -/* We use RUN_STATE__MAX but any invalid value will do */ -static RunState vmstop_requested = RUN_STATE__MAX; -static QemuMutex vmstop_lock; - -typedef struct { - RunState from; - RunState to; -} RunStateTransition; - -static const RunStateTransition runstate_transitions_def[] = { - /* from -> to */ - { RUN_STATE_PRECONFIG, RUN_STATE_PRELAUNCH }, - /* Early switch to inmigrate state to allow -incoming CLI option work - * as it used to. TODO: delay actual switching to inmigrate state to - * the point after machine is built and remove this hack. - */ - { RUN_STATE_PRECONFIG, RUN_STATE_INMIGRATE }, - - { RUN_STATE_DEBUG, RUN_STATE_RUNNING }, - { RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_DEBUG, RUN_STATE_PRELAUNCH }, - - { RUN_STATE_INMIGRATE, RUN_STATE_INTERNAL_ERROR }, - { RUN_STATE_INMIGRATE, RUN_STATE_IO_ERROR }, - { RUN_STATE_INMIGRATE, RUN_STATE_PAUSED }, - { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING }, - { RUN_STATE_INMIGRATE, RUN_STATE_SHUTDOWN }, - { RUN_STATE_INMIGRATE, RUN_STATE_SUSPENDED }, - { RUN_STATE_INMIGRATE, RUN_STATE_WATCHDOG }, - { RUN_STATE_INMIGRATE, RUN_STATE_GUEST_PANICKED }, - { RUN_STATE_INMIGRATE, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH }, - { RUN_STATE_INMIGRATE, RUN_STATE_POSTMIGRATE }, - { RUN_STATE_INMIGRATE, RUN_STATE_COLO }, - - { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED }, - { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PRELAUNCH }, - - { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING }, - { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_IO_ERROR, RUN_STATE_PRELAUNCH }, - - { RUN_STATE_PAUSED, RUN_STATE_RUNNING }, - { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_PAUSED, RUN_STATE_POSTMIGRATE }, - { RUN_STATE_PAUSED, RUN_STATE_PRELAUNCH }, - { RUN_STATE_PAUSED, RUN_STATE_COLO}, - - { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING }, - { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_POSTMIGRATE, RUN_STATE_PRELAUNCH }, - - { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING }, - { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE }, - - { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING }, - { RUN_STATE_FINISH_MIGRATE, RUN_STATE_PAUSED }, - { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE }, - { RUN_STATE_FINISH_MIGRATE, RUN_STATE_PRELAUNCH }, - { RUN_STATE_FINISH_MIGRATE, RUN_STATE_COLO}, - - { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING }, - { RUN_STATE_RESTORE_VM, RUN_STATE_PRELAUNCH }, - - { RUN_STATE_COLO, RUN_STATE_RUNNING }, - - { RUN_STATE_RUNNING, RUN_STATE_DEBUG }, - { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR }, - { RUN_STATE_RUNNING, RUN_STATE_IO_ERROR }, - { RUN_STATE_RUNNING, RUN_STATE_PAUSED }, - { RUN_STATE_RUNNING, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_RUNNING, RUN_STATE_RESTORE_VM }, - { RUN_STATE_RUNNING, RUN_STATE_SAVE_VM }, - { RUN_STATE_RUNNING, RUN_STATE_SHUTDOWN }, - { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG }, - { RUN_STATE_RUNNING, RUN_STATE_GUEST_PANICKED }, - { RUN_STATE_RUNNING, RUN_STATE_COLO}, - - { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING }, - - { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED }, - { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_SHUTDOWN, RUN_STATE_PRELAUNCH }, - { RUN_STATE_SHUTDOWN, RUN_STATE_COLO }, - - { RUN_STATE_DEBUG, RUN_STATE_SUSPENDED }, - { RUN_STATE_RUNNING, RUN_STATE_SUSPENDED }, - { RUN_STATE_SUSPENDED, RUN_STATE_RUNNING }, - { RUN_STATE_SUSPENDED, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_SUSPENDED, RUN_STATE_PRELAUNCH }, - { RUN_STATE_SUSPENDED, RUN_STATE_COLO}, - - { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING }, - { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_WATCHDOG, RUN_STATE_PRELAUNCH }, - { RUN_STATE_WATCHDOG, RUN_STATE_COLO}, - - { RUN_STATE_GUEST_PANICKED, RUN_STATE_RUNNING }, - { RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE }, - { RUN_STATE_GUEST_PANICKED, RUN_STATE_PRELAUNCH }, - - { RUN_STATE__MAX, RUN_STATE__MAX }, -}; - -static bool runstate_valid_transitions[RUN_STATE__MAX][RUN_STATE__MAX]; - -bool runstate_check(RunState state) -{ - return current_run_state == state; -} - -bool runstate_store(char *str, size_t size) -{ - const char *state = RunState_str(current_run_state); - size_t len = strlen(state) + 1; - - if (len > size) { - return false; - } - memcpy(str, state, len); - return true; -} - -static void runstate_init(void) -{ - const RunStateTransition *p; - - memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions)); - for (p = &runstate_transitions_def[0]; p->from != RUN_STATE__MAX; p++) { - runstate_valid_transitions[p->from][p->to] = true; - } - - qemu_mutex_init(&vmstop_lock); -} - -/* This function will abort() on invalid state transitions */ -void runstate_set(RunState new_state) -{ - assert(new_state < RUN_STATE__MAX); - - trace_runstate_set(current_run_state, RunState_str(current_run_state), - new_state, RunState_str(new_state)); - - if (current_run_state == new_state) { - return; - } - - if (!runstate_valid_transitions[current_run_state][new_state]) { - error_report("invalid runstate transition: '%s' -> '%s'", - RunState_str(current_run_state), - RunState_str(new_state)); - abort(); - } - - current_run_state = new_state; -} - -int runstate_is_running(void) -{ - return runstate_check(RUN_STATE_RUNNING); -} - -bool runstate_needs_reset(void) -{ - return runstate_check(RUN_STATE_INTERNAL_ERROR) || - runstate_check(RUN_STATE_SHUTDOWN); -} - -StatusInfo *qmp_query_status(Error **errp) -{ - StatusInfo *info = g_malloc0(sizeof(*info)); - - info->running = runstate_is_running(); - info->singlestep = singlestep; - info->status = current_run_state; - - return info; -} - -bool qemu_vmstop_requested(RunState *r) -{ - qemu_mutex_lock(&vmstop_lock); - *r = vmstop_requested; - vmstop_requested = RUN_STATE__MAX; - qemu_mutex_unlock(&vmstop_lock); - return *r < RUN_STATE__MAX; -} - -void qemu_system_vmstop_request_prepare(void) -{ - qemu_mutex_lock(&vmstop_lock); -} - -void qemu_system_vmstop_request(RunState state) -{ - vmstop_requested = state; - qemu_mutex_unlock(&vmstop_lock); - qemu_notify_event(); -} static int parse_name(void *opaque, QemuOpts *opts, Error **errp) { const char *proc_name; @@ -1015,8 +773,6 @@ static int usb_parse(const char *cmdline) /***********************************************************/ /* machine registration */ -MachineState *current_machine; - static MachineClass *find_machine(const char *name, GSList *machines) { GSList *el; @@ -1076,471 +832,6 @@ static int machine_help_func(QemuOpts *opts, MachineState *machine) return 1; } -struct VMChangeStateEntry { - VMChangeStateHandler *cb; - void *opaque; - QTAILQ_ENTRY(VMChangeStateEntry) entries; - int priority; -}; - -static QTAILQ_HEAD(, VMChangeStateEntry) vm_change_state_head = - QTAILQ_HEAD_INITIALIZER(vm_change_state_head); - -/** - * qemu_add_vm_change_state_handler_prio: - * @cb: the callback to invoke - * @opaque: user data passed to the callback - * @priority: low priorities execute first when the vm runs and the reverse is - * true when the vm stops - * - * Register a callback function that is invoked when the vm starts or stops - * running. - * - * Returns: an entry to be freed using qemu_del_vm_change_state_handler() - */ -VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( - VMChangeStateHandler *cb, void *opaque, int priority) -{ - VMChangeStateEntry *e; - VMChangeStateEntry *other; - - e = g_malloc0(sizeof(*e)); - e->cb = cb; - e->opaque = opaque; - e->priority = priority; - - /* Keep list sorted in ascending priority order */ - QTAILQ_FOREACH(other, &vm_change_state_head, entries) { - if (priority < other->priority) { - QTAILQ_INSERT_BEFORE(other, e, entries); - return e; - } - } - - QTAILQ_INSERT_TAIL(&vm_change_state_head, e, entries); - return e; -} - -VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, - void *opaque) -{ - return qemu_add_vm_change_state_handler_prio(cb, opaque, 0); -} - -void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) -{ - QTAILQ_REMOVE(&vm_change_state_head, e, entries); - g_free(e); -} - -void vm_state_notify(int running, RunState state) -{ - VMChangeStateEntry *e, *next; - - trace_vm_state_notify(running, state, RunState_str(state)); - - if (running) { - QTAILQ_FOREACH_SAFE(e, &vm_change_state_head, entries, next) { - e->cb(e->opaque, running, state); - } - } else { - QTAILQ_FOREACH_REVERSE_SAFE(e, &vm_change_state_head, entries, next) { - e->cb(e->opaque, running, state); - } - } -} - -static ShutdownCause reset_requested; -static ShutdownCause shutdown_requested; -static int shutdown_signal; -static pid_t shutdown_pid; -static int powerdown_requested; -static int debug_requested; -static int suspend_requested; -static bool preconfig_exit_requested = true; -static WakeupReason wakeup_reason; -static NotifierList powerdown_notifiers = - NOTIFIER_LIST_INITIALIZER(powerdown_notifiers); -static NotifierList suspend_notifiers = - NOTIFIER_LIST_INITIALIZER(suspend_notifiers); -static NotifierList wakeup_notifiers = - NOTIFIER_LIST_INITIALIZER(wakeup_notifiers); -static NotifierList shutdown_notifiers = - NOTIFIER_LIST_INITIALIZER(shutdown_notifiers); -static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE); - -ShutdownCause qemu_shutdown_requested_get(void) -{ - return shutdown_requested; -} - -ShutdownCause qemu_reset_requested_get(void) -{ - return reset_requested; -} - -static int qemu_shutdown_requested(void) -{ - return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE); -} - -static void qemu_kill_report(void) -{ - if (!qtest_driver() && shutdown_signal) { - if (shutdown_pid == 0) { - /* This happens for eg ^C at the terminal, so it's worth - * avoiding printing an odd message in that case. - */ - error_report("terminating on signal %d", shutdown_signal); - } else { - char *shutdown_cmd = qemu_get_pid_name(shutdown_pid); - - error_report("terminating on signal %d from pid " FMT_pid " (%s)", - shutdown_signal, shutdown_pid, - shutdown_cmd ? shutdown_cmd : "<unknown process>"); - g_free(shutdown_cmd); - } - shutdown_signal = 0; - } -} - -static ShutdownCause qemu_reset_requested(void) -{ - ShutdownCause r = reset_requested; - - if (r && replay_checkpoint(CHECKPOINT_RESET_REQUESTED)) { - reset_requested = SHUTDOWN_CAUSE_NONE; - return r; - } - return SHUTDOWN_CAUSE_NONE; -} - -static int qemu_suspend_requested(void) -{ - int r = suspend_requested; - if (r && replay_checkpoint(CHECKPOINT_SUSPEND_REQUESTED)) { - suspend_requested = 0; - return r; - } - return false; -} - -static WakeupReason qemu_wakeup_requested(void) -{ - return wakeup_reason; -} - -static int qemu_powerdown_requested(void) -{ - int r = powerdown_requested; - powerdown_requested = 0; - return r; -} - -static int qemu_debug_requested(void) -{ - int r = debug_requested; - debug_requested = 0; - return r; -} - -void qemu_exit_preconfig_request(void) -{ - preconfig_exit_requested = true; -} - -/* - * Reset the VM. Issue an event unless @reason is SHUTDOWN_CAUSE_NONE. - */ -void qemu_system_reset(ShutdownCause reason) -{ - MachineClass *mc; - - mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; - - cpu_synchronize_all_states(); - - if (mc && mc->reset) { - mc->reset(current_machine); - } else { - qemu_devices_reset(); - } - if (reason && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { - qapi_event_send_reset(shutdown_caused_by_guest(reason), reason); - } - cpu_synchronize_all_post_reset(); -} - -/* - * Wake the VM after suspend. - */ -static void qemu_system_wakeup(void) -{ - MachineClass *mc; - - mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; - - if (mc && mc->wakeup) { - mc->wakeup(current_machine); - } -} - -void qemu_system_guest_panicked(GuestPanicInformation *info) -{ - qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed"); - - if (current_cpu) { - current_cpu->crash_occurred = true; - } - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, - !!info, info); - vm_stop(RUN_STATE_GUEST_PANICKED); - if (!no_shutdown) { - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_POWEROFF, - !!info, info); - qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC); - } - - if (info) { - if (info->type == GUEST_PANIC_INFORMATION_TYPE_HYPER_V) { - qemu_log_mask(LOG_GUEST_ERROR, "\nHV crash parameters: (%#"PRIx64 - " %#"PRIx64" %#"PRIx64" %#"PRIx64" %#"PRIx64")\n", - info->u.hyper_v.arg1, - info->u.hyper_v.arg2, - info->u.hyper_v.arg3, - info->u.hyper_v.arg4, - info->u.hyper_v.arg5); - } else if (info->type == GUEST_PANIC_INFORMATION_TYPE_S390) { - qemu_log_mask(LOG_GUEST_ERROR, " on cpu %d: %s\n" - "PSW: 0x%016" PRIx64 " 0x%016" PRIx64"\n", - info->u.s390.core, - S390CrashReason_str(info->u.s390.reason), - info->u.s390.psw_mask, - info->u.s390.psw_addr); - } - qapi_free_GuestPanicInformation(info); - } -} - -void qemu_system_guest_crashloaded(GuestPanicInformation *info) -{ - qemu_log_mask(LOG_GUEST_ERROR, "Guest crash loaded"); - - qapi_event_send_guest_crashloaded(GUEST_PANIC_ACTION_RUN, - !!info, info); - - if (info) { - qapi_free_GuestPanicInformation(info); - } -} - -void qemu_system_reset_request(ShutdownCause reason) -{ - if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { - shutdown_requested = reason; - } else { - reset_requested = reason; - } - cpu_stop_current(); - qemu_notify_event(); -} - -static void qemu_system_suspend(void) -{ - pause_all_vcpus(); - notifier_list_notify(&suspend_notifiers, NULL); - runstate_set(RUN_STATE_SUSPENDED); - qapi_event_send_suspend(); -} - -void qemu_system_suspend_request(void) -{ - if (runstate_check(RUN_STATE_SUSPENDED)) { - return; - } - suspend_requested = 1; - cpu_stop_current(); - qemu_notify_event(); -} - -void qemu_register_suspend_notifier(Notifier *notifier) -{ - notifier_list_add(&suspend_notifiers, notifier); -} - -void qemu_system_wakeup_request(WakeupReason reason, Error **errp) -{ - trace_system_wakeup_request(reason); - - if (!runstate_check(RUN_STATE_SUSPENDED)) { - error_setg(errp, - "Unable to wake up: guest is not in suspended state"); - return; - } - if (!(wakeup_reason_mask & (1 << reason))) { - return; - } - runstate_set(RUN_STATE_RUNNING); - wakeup_reason = reason; - qemu_notify_event(); -} - -void qemu_system_wakeup_enable(WakeupReason reason, bool enabled) -{ - if (enabled) { - wakeup_reason_mask |= (1 << reason); - } else { - wakeup_reason_mask &= ~(1 << reason); - } -} - -void qemu_register_wakeup_notifier(Notifier *notifier) -{ - notifier_list_add(&wakeup_notifiers, notifier); -} - -void qemu_register_wakeup_support(void) -{ - wakeup_suspend_enabled = true; -} - -bool qemu_wakeup_suspend_enabled(void) -{ - return wakeup_suspend_enabled; -} - -void qemu_system_killed(int signal, pid_t pid) -{ - shutdown_signal = signal; - shutdown_pid = pid; - no_shutdown = 0; - - /* Cannot call qemu_system_shutdown_request directly because - * we are in a signal handler. - */ - shutdown_requested = SHUTDOWN_CAUSE_HOST_SIGNAL; - qemu_notify_event(); -} - -void qemu_system_shutdown_request(ShutdownCause reason) -{ - trace_qemu_system_shutdown_request(reason); - replay_shutdown_request(reason); - shutdown_requested = reason; - qemu_notify_event(); -} - -static void qemu_system_powerdown(void) -{ - qapi_event_send_powerdown(); - notifier_list_notify(&powerdown_notifiers, NULL); -} - -static void qemu_system_shutdown(ShutdownCause cause) -{ - qapi_event_send_shutdown(shutdown_caused_by_guest(cause), cause); - notifier_list_notify(&shutdown_notifiers, &cause); -} - -void qemu_system_powerdown_request(void) -{ - trace_qemu_system_powerdown_request(); - powerdown_requested = 1; - qemu_notify_event(); -} - -void qemu_register_powerdown_notifier(Notifier *notifier) -{ - notifier_list_add(&powerdown_notifiers, notifier); -} - -void qemu_register_shutdown_notifier(Notifier *notifier) -{ - notifier_list_add(&shutdown_notifiers, notifier); -} - -void qemu_system_debug_request(void) -{ - debug_requested = 1; - qemu_notify_event(); -} - -static bool main_loop_should_exit(void) -{ - RunState r; - ShutdownCause request; - - if (preconfig_exit_requested) { - if (runstate_check(RUN_STATE_PRECONFIG)) { - runstate_set(RUN_STATE_PRELAUNCH); - } - preconfig_exit_requested = false; - return true; - } - if (qemu_debug_requested()) { - vm_stop(RUN_STATE_DEBUG); - } - if (qemu_suspend_requested()) { - qemu_system_suspend(); - } - request = qemu_shutdown_requested(); - if (request) { - qemu_kill_report(); - qemu_system_shutdown(request); - if (no_shutdown) { - vm_stop(RUN_STATE_SHUTDOWN); - } else { - return true; - } - } - request = qemu_reset_requested(); - if (request) { - pause_all_vcpus(); - qemu_system_reset(request); - resume_all_vcpus(); - /* - * runstate can change in pause_all_vcpus() - * as iothread mutex is unlocked - */ - if (!runstate_check(RUN_STATE_RUNNING) && - !runstate_check(RUN_STATE_INMIGRATE) && - !runstate_check(RUN_STATE_FINISH_MIGRATE)) { - runstate_set(RUN_STATE_PRELAUNCH); - } - } - if (qemu_wakeup_requested()) { - pause_all_vcpus(); - qemu_system_wakeup(); - notifier_list_notify(&wakeup_notifiers, &wakeup_reason); - wakeup_reason = QEMU_WAKEUP_REASON_NONE; - resume_all_vcpus(); - qapi_event_send_wakeup(); - } - if (qemu_powerdown_requested()) { - qemu_system_powerdown(); - } - if (qemu_vmstop_requested(&r)) { - vm_stop(r); - } - return false; -} - -void qemu_main_loop(void) -{ -#ifdef CONFIG_PROFILER - int64_t ti; -#endif - while (!main_loop_should_exit()) { -#ifdef CONFIG_PROFILER - ti = profile_getclock(); -#endif - main_loop_wait(false); -#ifdef CONFIG_PROFILER - dev_time += profile_getclock() - ti; -#endif - } -} - static void version(void) { printf("QEMU emulator version " QEMU_FULL_VERSION "\n" @@ -2260,21 +1551,6 @@ static MachineClass *machine_parse(const char *name, GSList *machines) return mc; } -void qemu_add_exit_notifier(Notifier *notify) -{ - notifier_list_add(&exit_notifiers, notify); -} - -void qemu_remove_exit_notifier(Notifier *notify) -{ - notifier_remove(notify); -} - -static void qemu_run_exit_notifiers(void) -{ - notifier_list_notify(&exit_notifiers, NULL); -} - static const char *pid_file; static Notifier qemu_unlink_pidfile_notifier; @@ -2450,11 +1726,7 @@ static bool object_create_early(const char *type, QemuOpts *opts) return false; } - /* Memory allocation by backends needs to be done - * after configure_accelerator() (due to the tcg_enabled() - * checks at memory_region_init_*()). - * - * Also, allocation of large amounts of memory may delay + /* Allocation of large amounts of memory may delay * chardev initialization for too long, and trigger timeouts * on software that waits for a monitor socket to be created * (e.g. libvirt). @@ -2887,17 +2159,17 @@ static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp) static void configure_accelerators(const char *progname) { - const char *accel; + const char *accelerators; bool init_failed = false; qemu_opts_foreach(qemu_find_opts("icount"), do_configure_icount, NULL, &error_fatal); - accel = qemu_opt_get(qemu_get_machine_opts(), "accel"); + accelerators = qemu_opt_get(qemu_get_machine_opts(), "accel"); if (QTAILQ_EMPTY(&qemu_accel_opts.head)) { char **accel_list, **tmp; - if (accel == NULL) { + if (accelerators == NULL) { /* Select the default accelerator */ bool have_tcg = accel_find("tcg"); bool have_kvm = accel_find("kvm"); @@ -2905,21 +2177,21 @@ static void configure_accelerators(const char *progname) if (have_tcg && have_kvm) { if (g_str_has_suffix(progname, "kvm")) { /* If the program name ends with "kvm", we prefer KVM */ - accel = "kvm:tcg"; + accelerators = "kvm:tcg"; } else { - accel = "tcg:kvm"; + accelerators = "tcg:kvm"; } } else if (have_kvm) { - accel = "kvm"; + accelerators = "kvm"; } else if (have_tcg) { - accel = "tcg"; + accelerators = "tcg"; } else { error_report("No accelerator selected and" " no default accelerator available"); exit(1); } } - accel_list = g_strsplit(accel, ":", 0); + accel_list = g_strsplit(accelerators, ":", 0); for (tmp = accel_list; *tmp; tmp++) { /* @@ -2935,7 +2207,7 @@ static void configure_accelerators(const char *progname) } g_strfreev(accel_list); } else { - if (accel != NULL) { + if (accelerators != NULL) { error_report("The -accel and \"-machine accel=\" options are incompatible"); exit(1); } @@ -3005,9 +2277,8 @@ static void qemu_validate_options(void) "mutually exclusive"); exit(EXIT_FAILURE); } - if (incoming && preconfig_requested) { - error_report("'preconfig' and 'incoming' options are " - "mutually exclusive"); + if (incoming && preconfig_requested && strcmp(incoming, "defer") != 0) { + error_report("'preconfig' supports '-incoming defer' only"); exit(EXIT_FAILURE); } @@ -3038,6 +2309,26 @@ static void qemu_process_sugar_options(void) } } +/* -action processing */ + +/* + * Process all the -action parameters parsed from cmdline. + */ +static int process_runstate_actions(void *opaque, QemuOpts *opts, Error **errp) +{ + Error *local_err = NULL; + QDict *qdict = qemu_opts_to_qdict(opts, NULL); + QObject *ret = NULL; + qmp_marshal_set_action(qdict, &ret, &local_err); + qobject_unref(ret); + qobject_unref(qdict); + if (local_err) { + error_propagate(errp, local_err); + return 1; + } + return 0; +} + static void qemu_process_early_options(void) { #ifdef CONFIG_SECCOMP @@ -3050,6 +2341,11 @@ static void qemu_process_early_options(void) qemu_opts_foreach(qemu_find_opts("name"), parse_name, NULL, &error_fatal); + if (qemu_opts_foreach(qemu_find_opts("action"), + process_runstate_actions, NULL, &error_fatal)) { + exit(1); + } + #ifndef _WIN32 qemu_opts_foreach(qemu_find_opts("add-fd"), parse_add_fd, NULL, &error_fatal); @@ -3121,39 +2417,6 @@ static void qemu_maybe_daemonize(const char *pid_file) qemu_add_exit_notifier(&qemu_unlink_pidfile_notifier); } -static void qemu_init_subsystems(void) -{ - Error *err; - - os_set_line_buffering(); - - module_call_init(MODULE_INIT_TRACE); - - qemu_init_cpu_list(); - qemu_init_cpu_loop(); - qemu_mutex_lock_iothread(); - - atexit(qemu_run_exit_notifiers); - - module_call_init(MODULE_INIT_QOM); - module_call_init(MODULE_INIT_MIGRATION); - - runstate_init(); - precopy_infrastructure_init(); - postcopy_infrastructure_init(); - monitor_init_globals(); - - if (qcrypto_init(&err) < 0) { - error_reportf_err(err, "cannot initialize crypto: "); - exit(1); - } - - os_setup_early_signal_handling(); - - bdrv_init_with_whitelist(); - socket_init(); -} - static void qemu_init_displays(void) { DisplayState *ds; @@ -3176,10 +2439,6 @@ static void qemu_init_displays(void) } } -/* - * Called after leaving preconfig state. From here on runstate is - * RUN_STATE_PRELAUNCH or RUN_STATE_INMIGRATE. - */ static void qemu_init_board(void) { MachineClass *machine_class = MACHINE_GET_CLASS(current_machine); @@ -3190,10 +2449,9 @@ static void qemu_init_board(void) } /* process plugin before CPUs are created, but once -smp has been parsed */ - if (qemu_plugin_load_list(&plugin_list)) { - exit(1); - } + qemu_plugin_load_list(&plugin_list, &error_fatal); + /* From here on we enter MACHINE_PHASE_INITIALIZED. */ machine_run_board_init(current_machine); /* @@ -3234,8 +2492,6 @@ static void qemu_create_cli_devices(void) static void qemu_machine_creation_done(void) { - cpu_synchronize_all_post_init(); - /* Did we create any drives that we failed to create a device for? */ drive_check_orphaned(); @@ -3253,42 +2509,48 @@ static void qemu_machine_creation_done(void) qdev_prop_check_globals(); - if (current_machine->boot_once) { - qemu_boot_set(current_machine->boot_once, &error_fatal); - qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_order)); - } + qdev_machine_creation_done(); if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) { exit(1); } +} - qdev_machine_creation_done(); +void qmp_x_exit_preconfig(Error **errp) +{ + if (phase_check(PHASE_MACHINE_INITIALIZED)) { + error_setg(errp, "The command is permitted only before machine initialization"); + return; + } - /* TODO: once all bus devices are qdevified, this should be done - * when bus is created by qdev.c */ - /* - * TODO: If we had a main 'reset container' that the whole system - * lived in, we could reset that using the multi-phase reset - * APIs. For the moment, we just reset the sysbus, which will cause - * all devices hanging off it (and all their child buses, recursively) - * to be reset. Note that this will *not* reset any Device objects - * which are not attached to some part of the qbus tree! - */ - qemu_register_reset(resettable_cold_reset_fn, sysbus_get_default()); - qemu_run_machine_init_done_notifiers(); + qemu_init_board(); + qemu_create_cli_devices(); + qemu_machine_creation_done(); - if (rom_check_and_register_reset() != 0) { - exit(1); + if (loadvm) { + Error *local_err = NULL; + if (load_snapshot(loadvm, &local_err) < 0) { + error_report_err(local_err); + autostart = 0; + exit(1); + } + } + if (replay_mode != REPLAY_MODE_NONE) { + replay_vmstate_init(); } - replay_start(); - - /* This checkpoint is required by replay to separate prior clock - reading from the other reads, because timer polling functions query - clock values from the log. */ - replay_checkpoint(CHECKPOINT_RESET); - qemu_system_reset(SHUTDOWN_CAUSE_NONE); - register_global_state(); + if (incoming) { + Error *local_err = NULL; + if (strcmp(incoming, "defer") != 0) { + qmp_migrate_incoming(incoming, &local_err); + if (local_err) { + error_reportf_err(local_err, "-incoming %s: ", incoming); + exit(1); + } + } + } else if (autostart) { + qmp_cont(NULL); + } } void qemu_init(int argc, char **argv, char **envp) @@ -3326,7 +2588,6 @@ void qemu_init(int argc, char **argv, char **envp) qemu_add_opts(&qemu_add_fd_opts); qemu_add_opts(&qemu_object_opts); qemu_add_opts(&qemu_tpmdev_opts); - qemu_add_opts(&qemu_realtime_opts); qemu_add_opts(&qemu_overcommit_opts); qemu_add_opts(&qemu_msg_opts); qemu_add_opts(&qemu_name_opts); @@ -3334,6 +2595,7 @@ void qemu_init(int argc, char **argv, char **envp) qemu_add_opts(&qemu_icount_opts); qemu_add_opts(&qemu_semihosting_config_opts); qemu_add_opts(&qemu_fw_cfg_opts); + qemu_add_opts(&qemu_action_opts); module_call_init(MODULE_INIT_OPTS); error_init(argv[0]); @@ -3784,6 +3046,12 @@ void qemu_init(int argc, char **argv, char **envp) } watchdog = optarg; break; + case QEMU_OPTION_action: + olist = qemu_find_opts("action"); + if (!qemu_opts_parse_noisily(olist, optarg, false)) { + exit(1); + } + break; case QEMU_OPTION_watchdog_action: if (select_watchdog_action(optarg) == -1) { error_report("unknown -watchdog-action parameter"); @@ -3855,7 +3123,6 @@ void qemu_init(int argc, char **argv, char **envp) } break; case QEMU_OPTION_preconfig: - preconfig_exit_requested = false; preconfig_requested = true; break; case QEMU_OPTION_enable_kvm: @@ -3930,18 +3197,12 @@ void qemu_init(int argc, char **argv, char **envp) qemu_opts_parse_noisily(olist, "hpet=off", false); break; case QEMU_OPTION_no_reboot: - no_reboot = 1; + olist = qemu_find_opts("action"); + qemu_opts_parse_noisily(olist, "reboot=shutdown", false); break; case QEMU_OPTION_no_shutdown: - no_shutdown = 1; - break; - case QEMU_OPTION_show_cursor: - warn_report("The -show-cursor option is deprecated. Please " - "add show-cursor=on to your -display options."); - warn_report("When using the default display you can use " - "-display default,show-cursor=on"); - dpy.has_show_cursor = true; - dpy.show_cursor = true; + olist = qemu_find_opts("action"); + qemu_opts_parse_noisily(olist, "panic=pause,shutdown=pause", false); break; case QEMU_OPTION_uuid: if (qemu_uuid_parse(optarg, &qemu_uuid) < 0) { @@ -4004,14 +3265,6 @@ void qemu_init(int argc, char **argv, char **envp) exit(1); } break; - case QEMU_OPTION_tb_size: -#ifndef CONFIG_TCG - error_report("TCG is disabled"); - exit(1); -#endif - warn_report("The -tb-size option is deprecated, use -accel tcg,tb-size instead"); - object_register_sugar_prop(ACCEL_CLASS_NAME("tcg"), "tb-size", optarg); - break; case QEMU_OPTION_icount: icount_opts = qemu_opts_parse_noisily(qemu_find_opts("icount"), optarg, true); @@ -4144,27 +3397,13 @@ void qemu_init(int argc, char **argv, char **envp) exit(1); } break; - case QEMU_OPTION_realtime: - warn_report("'-realtime mlock=...' is deprecated, please use " - "'-overcommit mem-lock=...' instead"); - opts = qemu_opts_parse_noisily(qemu_find_opts("realtime"), - optarg, false); - if (!opts) { - exit(1); - } - /* Don't override the -overcommit option if set */ - enable_mlock = enable_mlock || - qemu_opt_get_bool(opts, "mlock", true); - break; case QEMU_OPTION_overcommit: opts = qemu_opts_parse_noisily(qemu_find_opts("overcommit"), optarg, false); if (!opts) { exit(1); } - /* Don't override the -realtime option if set */ - enable_mlock = enable_mlock || - qemu_opt_get_bool(opts, "mem-lock", false); + enable_mlock = qemu_opt_get_bool(opts, "mem-lock", false); enable_cpu_pm = qemu_opt_get_bool(opts, "cpu-pm", false); break; case QEMU_OPTION_msg: @@ -4229,17 +3468,21 @@ void qemu_init(int argc, char **argv, char **envp) qemu_create_machine(select_machine()); + suspend_mux_open(); + qemu_disable_default_devices(); qemu_create_default_devices(); qemu_create_early_backends(); qemu_apply_machine_options(); + phase_advance(PHASE_MACHINE_CREATED); /* * Note: uses machine properties such as kernel-irqchip, must run * after machine_set_property(). */ configure_accelerators(argv[0]); + phase_advance(PHASE_ACCEL_CREATED); /* * Beware, QOM objects created before this point miss global and @@ -4280,95 +3523,17 @@ void qemu_init(int argc, char **argv, char **envp) qemu_resolve_machine_memdev(); parse_numa_opts(current_machine); - if (preconfig_requested) { - qemu_init_displays(); - } - - /* do monitor/qmp handling at preconfig state if requested */ - qemu_main_loop(); - - qemu_init_board(); - - qemu_create_cli_devices(); - - /* initialize displays after all errors have been reported */ - if (!preconfig_requested) { - qemu_init_displays(); - } - qemu_machine_creation_done(); - - if (loadvm) { - Error *local_err = NULL; - if (load_snapshot(loadvm, &local_err) < 0) { - error_report_err(local_err); - autostart = 0; - exit(1); - } - } - if (replay_mode != REPLAY_MODE_NONE) { - replay_vmstate_init(); - } - if (vmstate_dump_file) { /* dump and exit */ dump_vmstate_json_to_file(vmstate_dump_file); exit(0); } - if (incoming) { - Error *local_err = NULL; - if (strcmp(incoming, "defer") != 0) { - qmp_migrate_incoming(incoming, &local_err); - if (local_err) { - error_reportf_err(local_err, "-incoming %s: ", incoming); - exit(1); - } - } - } else if (autostart) { - qmp_cont(NULL); - } + qemu_init_displays(); + if (!preconfig_requested) { + qmp_x_exit_preconfig(&error_fatal); + } accel_setup_post(current_machine); os_setup_post(); - - return; -} - -void qemu_cleanup(void) -{ - gdbserver_cleanup(); - - /* - * cleaning up the migration object cancels any existing migration - * try to do this early so that it also stops using devices. - */ - migration_shutdown(); - - /* - * We must cancel all block jobs while the block layer is drained, - * or cancelling will be affected by throttling and thus may block - * for an extended period of time. - * vm_shutdown() will bdrv_drain_all(), so we may as well include - * it in the drained section. - * We do not need to end this section, because we do not want any - * requests happening from here on anyway. - */ - bdrv_drain_all_begin(); - - /* No more vcpu or device emulation activity beyond this point */ - vm_shutdown(); - replay_finish(); - - job_cancel_sync_all(); - bdrv_close_all(); - - res_free(); - - /* vhost-user must be cleaned up before chardevs. */ - tpm_cleanup(); - net_cleanup(); - audio_cleanup(); - monitor_cleanup(); - qemu_chr_cleanup(); - user_creatable_cleanup(); - /* TODO: unref root container, check all devices are ok */ + resume_mux_open(); } diff --git a/stubs/machine-init-done.c b/stubs/machine-init-done.c deleted file mode 100644 index cd8e81392d..0000000000 --- a/stubs/machine-init-done.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "qemu/osdep.h" -#include "sysemu/sysemu.h" - -bool machine_init_done = true; - -void qemu_add_machine_init_done_notifier(Notifier *notify) -{ -} diff --git a/stubs/meson.build b/stubs/meson.build index 82b7ba60ab..80b1d81a31 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -21,7 +21,6 @@ stub_ss.add(files('iothread-lock.c')) stub_ss.add(files('isa-bus.c')) stub_ss.add(files('is-daemonized.c')) stub_ss.add(when: 'CONFIG_LINUX_AIO', if_true: files('linux-aio.c')) -stub_ss.add(files('machine-init-done.c')) stub_ss.add(files('migr-blocker.c')) stub_ss.add(files('monitor.c')) stub_ss.add(files('monitor-core.c')) @@ -29,6 +28,7 @@ stub_ss.add(files('pci-bus.c')) stub_ss.add(files('pci-host-piix.c')) stub_ss.add(files('qemu-timer-notify-cb.c')) stub_ss.add(files('qmp_memory_device.c')) +stub_ss.add(files('qmp-command-available.c')) stub_ss.add(files('qtest.c')) stub_ss.add(files('ram-block.c')) stub_ss.add(files('ramfb.c')) diff --git a/stubs/qmp-command-available.c b/stubs/qmp-command-available.c new file mode 100644 index 0000000000..46540af7bf --- /dev/null +++ b/stubs/qmp-command-available.c @@ -0,0 +1,7 @@ +#include "qemu/osdep.h" +#include "qapi/qmp/dispatch.h" + +bool qmp_command_available(const QmpCommand *cmd, Error **errp) +{ + return true; +} diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py index e2a214bdab..83bfc3b6bb 100644 --- a/tests/migration/guestperf/engine.py +++ b/tests/migration/guestperf/engine.py @@ -304,7 +304,7 @@ class Engine(object): argv_source += ["-mem-path", "/dev/shm", "-mem-prealloc"] if hardware._locked_pages: - argv_source += ["-realtime", "mlock=on"] + argv_source += ["-overcommit", "mem-lock=on"] if hardware._huge_pages: pass diff --git a/tests/qtest/fuzz-test.c b/tests/qtest/fuzz-test.c index 87b72307a5..cdb1100a0b 100644 --- a/tests/qtest/fuzz-test.c +++ b/tests/qtest/fuzz-test.c @@ -48,6 +48,55 @@ static void test_lp1878642_pci_bus_get_irq_level_assert(void) qtest_quit(s); } +/* + * Here a MemoryRegionCache pointed to an MMIO region but had a + * larger size than the underlying region. + */ +static void test_mmio_oob_from_memory_region_cache(void) +{ + QTestState *s; + + s = qtest_init("-M pc-q35-5.2 -display none -m 512M " + "-device virtio-scsi,num_queues=8,addr=03.0 "); + + qtest_outl(s, 0xcf8, 0x80001811); + qtest_outb(s, 0xcfc, 0x6e); + qtest_outl(s, 0xcf8, 0x80001824); + qtest_outl(s, 0xcf8, 0x80001813); + qtest_outl(s, 0xcfc, 0xa080000); + qtest_outl(s, 0xcf8, 0x80001802); + qtest_outl(s, 0xcfc, 0x5a175a63); + qtest_outb(s, 0x6e08, 0x9e); + qtest_writeb(s, 0x9f003, 0xff); + qtest_writeb(s, 0x9f004, 0x01); + qtest_writeb(s, 0x9e012, 0x0e); + qtest_writeb(s, 0x9e01b, 0x0e); + qtest_writeb(s, 0x9f006, 0x01); + qtest_writeb(s, 0x9f008, 0x01); + qtest_writeb(s, 0x9f00a, 0x01); + qtest_writeb(s, 0x9f00c, 0x01); + qtest_writeb(s, 0x9f00e, 0x01); + qtest_writeb(s, 0x9f010, 0x01); + qtest_writeb(s, 0x9f012, 0x01); + qtest_writeb(s, 0x9f014, 0x01); + qtest_writeb(s, 0x9f016, 0x01); + qtest_writeb(s, 0x9f018, 0x01); + qtest_writeb(s, 0x9f01a, 0x01); + qtest_writeb(s, 0x9f01c, 0x01); + qtest_writeb(s, 0x9f01e, 0x01); + qtest_writeb(s, 0x9f020, 0x01); + qtest_writeb(s, 0x9f022, 0x01); + qtest_writeb(s, 0x9f024, 0x01); + qtest_writeb(s, 0x9f026, 0x01); + qtest_writeb(s, 0x9f028, 0x01); + qtest_writeb(s, 0x9f02a, 0x01); + qtest_writeb(s, 0x9f02c, 0x01); + qtest_writeb(s, 0x9f02e, 0x01); + qtest_writeb(s, 0x9f030, 0x01); + qtest_outb(s, 0x6e10, 0x00); + qtest_quit(s); +} + int main(int argc, char **argv) { const char *arch = qtest_get_arch(); @@ -59,6 +108,8 @@ int main(int argc, char **argv) test_lp1878263_megasas_zero_iov_cnt); qtest_add_func("fuzz/test_lp1878642_pci_bus_get_irq_level_assert", test_lp1878642_pci_bus_get_irq_level_assert); + qtest_add_func("fuzz/test_mmio_oob_from_memory_region_cache", + test_mmio_oob_from_memory_region_cache); } return g_test_run(); diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c index 016b32ebee..6dcad2db49 100644 --- a/tests/qtest/pvpanic-test.c +++ b/tests/qtest/pvpanic-test.c @@ -11,13 +11,36 @@ #include "libqos/libqtest.h" #include "qapi/qmp/qdict.h" +static void test_panic_nopause(void) +{ + uint8_t val; + QDict *response, *data; + QTestState *qts; + + qts = qtest_init("-device pvpanic -action panic=none"); + + val = qtest_inb(qts, 0x505); + g_assert_cmpuint(val, ==, 3); + + qtest_outb(qts, 0x505, 0x1); + + response = qtest_qmp_eventwait_ref(qts, "GUEST_PANICKED"); + g_assert(qdict_haskey(response, "data")); + data = qdict_get_qdict(response, "data"); + g_assert(qdict_haskey(data, "action")); + g_assert_cmpstr(qdict_get_str(data, "action"), ==, "run"); + qobject_unref(response); + + qtest_quit(qts); +} + static void test_panic(void) { uint8_t val; QDict *response, *data; QTestState *qts; - qts = qtest_init("-device pvpanic"); + qts = qtest_init("-device pvpanic -action panic=pause"); val = qtest_inb(qts, 0x505); g_assert_cmpuint(val, ==, 3); @@ -40,6 +63,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); qtest_add_func("/pvpanic/panic", test_panic); + qtest_add_func("/pvpanic/panic-nopause", test_panic_nopause); ret = g_test_run(); diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c index eb1cd8abb8..11614bf63f 100644 --- a/tests/qtest/qmp-test.c +++ b/tests/qtest/qmp-test.c @@ -295,7 +295,7 @@ static void test_qmp_preconfig(void) rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }"); ret = qdict_get_qdict(rsp, "return"); g_assert(ret); - g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig"); + g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "prelaunch"); qobject_unref(rsp); /* exit preconfig state */ diff --git a/tests/tcg/arm/fcvt.c b/tests/tcg/arm/fcvt.c index 617626bc63..7ac47b564e 100644 --- a/tests/tcg/arm/fcvt.c +++ b/tests/tcg/arm/fcvt.c @@ -73,11 +73,9 @@ static void print_int64(int i, int64_t num) #ifndef SNANF /* Signaling NaN macros, if supported. */ -# if __GNUC_PREREQ(3, 3) -# define SNANF (__builtin_nansf ("")) -# define SNAN (__builtin_nans ("")) -# define SNANL (__builtin_nansl ("")) -# endif +# define SNANF (__builtin_nansf ("")) +# define SNAN (__builtin_nans ("")) +# define SNANL (__builtin_nansl ("")) #endif float single_numbers[] = { -SNANF, diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h index 30b18b4966..a090040bb2 100644 --- a/tools/virtiofsd/fuse_common.h +++ b/tools/virtiofsd/fuse_common.h @@ -807,15 +807,6 @@ void fuse_remove_signal_handlers(struct fuse_session *se); * * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags! */ - -#if defined(__GNUC__) && \ - (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \ - !defined __cplusplus -_Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit"); -#else -struct _fuse_off_t_must_be_64bit_dummy_struct { - unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); -}; -#endif +QEMU_BUILD_BUG_ON(sizeof(off_t) != 8); #endif /* FUSE_COMMON_H_ */ diff --git a/ui/console.c b/ui/console.c index 30e70be555..4db5b04cc2 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1345,7 +1345,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, if (QTAILQ_EMPTY(&consoles)) { s->index = 0; QTAILQ_INSERT_TAIL(&consoles, s, next); - } else if (console_type != GRAPHIC_CONSOLE || qdev_hotplug) { + } else if (console_type != GRAPHIC_CONSOLE || phase_check(PHASE_MACHINE_READY)) { QemuConsole *last = QTAILQ_LAST(&consoles); s->index = last->index + 1; QTAILQ_INSERT_TAIL(&consoles, s, next); @@ -30,6 +30,7 @@ #include "ui/input.h" #include "ui/sdl2.h" #include "sysemu/runstate.h" +#include "sysemu/runstate-action.h" #include "sysemu/sysemu.h" #include "ui/win32-kbd-hook.h" @@ -606,7 +607,7 @@ static void handle_windowevent(SDL_Event *ev) allow_close = false; } if (allow_close) { - no_shutdown = 0; + shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); } } else { @@ -653,7 +654,7 @@ void sdl2_poll_events(struct sdl2_console *scon) allow_close = false; } if (allow_close) { - no_shutdown = 0; + shutdown_action = SHUTDOWN_ACTION_POWEROFF; qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); } break; diff --git a/util/qemu-option.c b/util/qemu-option.c index 25792159ba..c88e159f18 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -38,27 +38,19 @@ #include "qemu/help_option.h" /* - * Extracts the name of an option from the parameter string (p points at the + * Extracts the name of an option from the parameter string (@p points at the * first byte of the option name) * - * The option name is delimited by delim (usually , or =) or the string end - * and is copied into option. The caller is responsible for free'ing option - * when no longer required. + * The option name is @len characters long and is copied into @option. The + * caller is responsible for free'ing @option when no longer required. * * The return value is the position of the delimiter/zero byte after the option - * name in p. + * name in @p. */ -static const char *get_opt_name(const char *p, char **option, char delim) +static const char *get_opt_name(const char *p, char **option, size_t len) { - char *offset = strchr(p, delim); - - if (offset) { - *option = g_strndup(p, offset - p); - return offset; - } else { - *option = g_strdup(p); - return p + strlen(p); - } + *option = g_strndup(p, len); + return p + len; } /* @@ -468,16 +460,16 @@ static bool qemu_opt_parse(QemuOpt *opt, Error **errp) } } -static bool opts_accepts_any(const QemuOpts *opts) +static bool opts_accepts_any(const QemuOptsList *list) { - return opts->list->desc[0].name == NULL; + return list->desc[0].name == NULL; } int qemu_opt_unset(QemuOpts *opts, const char *name) { QemuOpt *opt = qemu_opt_find(opts, name); - assert(opts_accepts_any(opts)); + assert(opts_accepts_any(opts->list)); if (opt == NULL) { return -1; @@ -508,9 +500,10 @@ static bool opt_validate(QemuOpt *opt, bool *help_wanted, Error **errp) { const QemuOptDesc *desc; + const QemuOptsList *list = opt->opts->list; - desc = find_desc_by_name(opt->opts->list->desc, opt->name); - if (!desc && !opts_accepts_any(opt->opts)) { + desc = find_desc_by_name(list->desc, opt->name); + if (!desc && !opts_accepts_any(list)) { error_setg(errp, QERR_INVALID_PARAMETER, opt->name); if (help_wanted && is_help_option(opt->name)) { *help_wanted = true; @@ -543,9 +536,10 @@ bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, { QemuOpt *opt; const QemuOptDesc *desc; + const QemuOptsList *list = opts->list; - desc = find_desc_by_name(opts->list->desc, name); - if (!desc && !opts_accepts_any(opts)) { + desc = find_desc_by_name(list->desc, name); + if (!desc && !opts_accepts_any(list)) { error_setg(errp, QERR_INVALID_PARAMETER, name); return false; } @@ -565,9 +559,10 @@ bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, { QemuOpt *opt; const QemuOptDesc *desc; + const QemuOptsList *list = opts->list; - desc = find_desc_by_name(opts->list->desc, name); - if (!desc && !opts_accepts_any(opts)) { + desc = find_desc_by_name(list->desc, name); + if (!desc && !opts_accepts_any(list)) { error_setg(errp, QERR_INVALID_PARAMETER, name); return false; } @@ -766,12 +761,11 @@ static const char *get_opt_name_value(const char *params, const char *firstname, char **name, char **value) { - const char *p, *pe, *pc; - - pe = strchr(params, '='); - pc = strchr(params, ','); + const char *p; + size_t len; - if (!pe || (pc && pc < pe)) { + len = strcspn(params, "=,"); + if (params[len] != '=') { /* found "foo,more" */ if (firstname) { /* implicitly named first option */ @@ -779,7 +773,7 @@ static const char *get_opt_name_value(const char *params, p = get_opt_value(params, value); } else { /* option without value, must be a flag */ - p = get_opt_name(params, name, ','); + p = get_opt_name(params, name, len); if (strncmp(*name, "no", 2) == 0) { memmove(*name, *name + 2, strlen(*name + 2) + 1); *value = g_strdup("off"); @@ -789,7 +783,7 @@ static const char *get_opt_name_value(const char *params, } } else { /* found "foo=bar,more" */ - p = get_opt_name(params, name, '='); + p = get_opt_name(params, name, len); assert(*p == '='); p++; p = get_opt_value(p, value); @@ -1116,7 +1110,7 @@ bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) { QemuOpt *opt; - assert(opts_accepts_any(opts)); + assert(opts_accepts_any(opts->list)); QTAILQ_FOREACH(opt, &opts->head, next) { opt->desc = find_desc_by_name(desc, opt->name); |