2014-03-05 18:30:45 +01:00
|
|
|
/*
|
|
|
|
* QEMU Machine
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Red Hat Inc
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Marcel Apfelbaum <marcel.a@redhat.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
|
|
* See the COPYING file in the top-level directory.
|
|
|
|
*/
|
|
|
|
|
2016-01-26 19:17:29 +01:00
|
|
|
#include "qemu/osdep.h"
|
2019-06-20 07:45:24 +02:00
|
|
|
#include "qemu/option.h"
|
|
|
|
#include "qapi/qmp/qerror.h"
|
|
|
|
#include "sysemu/replay.h"
|
2018-06-25 14:41:58 +02:00
|
|
|
#include "qemu/units.h"
|
2014-03-05 18:30:45 +01:00
|
|
|
#include "hw/boards.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 09:01:28 +01:00
|
|
|
#include "qapi/error.h"
|
2018-02-11 10:36:01 +01:00
|
|
|
#include "qapi/qapi-visit-common.h"
|
2014-05-26 14:40:58 +02:00
|
|
|
#include "qapi/visitor.h"
|
2014-07-01 16:14:41 +02:00
|
|
|
#include "hw/sysbus.h"
|
|
|
|
#include "sysemu/sysemu.h"
|
2017-05-02 18:29:55 +02:00
|
|
|
#include "sysemu/numa.h"
|
2014-07-01 16:14:41 +02:00
|
|
|
#include "qemu/error-report.h"
|
2017-05-18 10:09:31 +02:00
|
|
|
#include "sysemu/qtest.h"
|
2018-12-12 16:36:30 +01:00
|
|
|
#include "hw/pci/pci.h"
|
2019-03-08 19:20:53 +01:00
|
|
|
#include "hw/mem/nvdimm.h"
|
2014-05-26 14:40:58 +02:00
|
|
|
|
2019-11-05 19:22:17 +01:00
|
|
|
GlobalProperty hw_compat_4_2[] = {
|
|
|
|
{ "virtio-blk-device", "x-enable-wce-if-config-wce", "off" },
|
2019-12-20 15:09:04 +01:00
|
|
|
{ "virtio-blk-device", "seg-max-adjust", "off"},
|
|
|
|
{ "virtio-scsi-device", "seg_max_adjust", "off"},
|
|
|
|
{ "vhost-blk-device", "seg_max_adjust", "off"},
|
2020-01-08 10:10:43 +01:00
|
|
|
{ "usb-host", "suppress-remote-wake", "off" },
|
2020-01-08 10:10:44 +01:00
|
|
|
{ "usb-redir", "suppress-remote-wake", "off" },
|
2020-02-06 08:43:58 +01:00
|
|
|
{ "qxl", "revision", "4" },
|
|
|
|
{ "qxl-vga", "revision", "4" },
|
2019-11-05 19:22:17 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);
|
|
|
|
|
2019-08-20 18:30:05 +02:00
|
|
|
GlobalProperty hw_compat_4_1[] = {
|
|
|
|
{ "virtio-pci", "x-pcie-flr-init", "off" },
|
virtio-pci: disable vring processing when bus-mastering is disabled
Currently the SLOF firmware for pseries guests will disable/re-enable
a PCI device multiple times via IO/MEM/MASTER bits of PCI_COMMAND
register after the initial probe/feature negotiation, as it tends to
work with a single device at a time at various stages like probing
and running block/network bootloaders without doing a full reset
in-between.
In QEMU, when PCI_COMMAND_MASTER is disabled we disable the
corresponding IOMMU memory region, so DMA accesses (including to vring
fields like idx/flags) will no longer undergo the necessary
translation. Normally we wouldn't expect this to happen since it would
be misbehavior on the driver side to continue driving DMA requests.
However, in the case of pseries, with iommu_platform=on, we trigger the
following sequence when tearing down the virtio-blk dataplane ioeventfd
in response to the guest unsetting PCI_COMMAND_MASTER:
#2 0x0000555555922651 in virtqueue_map_desc (vdev=vdev@entry=0x555556dbcfb0, p_num_sg=p_num_sg@entry=0x7fffe657e1a8, addr=addr@entry=0x7fffe657e240, iov=iov@entry=0x7fffe6580240, max_num_sg=max_num_sg@entry=1024, is_write=is_write@entry=false, pa=0, sz=0)
at /home/mdroth/w/qemu.git/hw/virtio/virtio.c:757
#3 0x0000555555922a89 in virtqueue_pop (vq=vq@entry=0x555556dc8660, sz=sz@entry=184)
at /home/mdroth/w/qemu.git/hw/virtio/virtio.c:950
#4 0x00005555558d3eca in virtio_blk_get_request (vq=0x555556dc8660, s=0x555556dbcfb0)
at /home/mdroth/w/qemu.git/hw/block/virtio-blk.c:255
#5 0x00005555558d3eca in virtio_blk_handle_vq (s=0x555556dbcfb0, vq=0x555556dc8660)
at /home/mdroth/w/qemu.git/hw/block/virtio-blk.c:776
#6 0x000055555591dd66 in virtio_queue_notify_aio_vq (vq=vq@entry=0x555556dc8660)
at /home/mdroth/w/qemu.git/hw/virtio/virtio.c:1550
#7 0x000055555591ecef in virtio_queue_notify_aio_vq (vq=0x555556dc8660)
at /home/mdroth/w/qemu.git/hw/virtio/virtio.c:1546
#8 0x000055555591ecef in virtio_queue_host_notifier_aio_poll (opaque=0x555556dc86c8)
at /home/mdroth/w/qemu.git/hw/virtio/virtio.c:2527
#9 0x0000555555d02164 in run_poll_handlers_once (ctx=ctx@entry=0x55555688bfc0, timeout=timeout@entry=0x7fffe65844a8)
at /home/mdroth/w/qemu.git/util/aio-posix.c:520
#10 0x0000555555d02d1b in try_poll_mode (timeout=0x7fffe65844a8, ctx=0x55555688bfc0)
at /home/mdroth/w/qemu.git/util/aio-posix.c:607
#11 0x0000555555d02d1b in aio_poll (ctx=ctx@entry=0x55555688bfc0, blocking=blocking@entry=true)
at /home/mdroth/w/qemu.git/util/aio-posix.c:639
#12 0x0000555555d0004d in aio_wait_bh_oneshot (ctx=0x55555688bfc0, cb=cb@entry=0x5555558d5130 <virtio_blk_data_plane_stop_bh>, opaque=opaque@entry=0x555556de86f0)
at /home/mdroth/w/qemu.git/util/aio-wait.c:71
#13 0x00005555558d59bf in virtio_blk_data_plane_stop (vdev=<optimized out>)
at /home/mdroth/w/qemu.git/hw/block/dataplane/virtio-blk.c:288
#14 0x0000555555b906a1 in virtio_bus_stop_ioeventfd (bus=bus@entry=0x555556dbcf38)
at /home/mdroth/w/qemu.git/hw/virtio/virtio-bus.c:245
#15 0x0000555555b90dbb in virtio_bus_stop_ioeventfd (bus=bus@entry=0x555556dbcf38)
at /home/mdroth/w/qemu.git/hw/virtio/virtio-bus.c:237
#16 0x0000555555b92a8e in virtio_pci_stop_ioeventfd (proxy=0x555556db4e40)
at /home/mdroth/w/qemu.git/hw/virtio/virtio-pci.c:292
#17 0x0000555555b92a8e in virtio_write_config (pci_dev=0x555556db4e40, address=<optimized out>, val=1048832, len=<optimized out>)
at /home/mdroth/w/qemu.git/hw/virtio/virtio-pci.c:613
I.e. the calling code is only scheduling a one-shot BH for
virtio_blk_data_plane_stop_bh, but somehow we end up trying to process
an additional virtqueue entry before we get there. This is likely due
to the following check in virtio_queue_host_notifier_aio_poll:
static bool virtio_queue_host_notifier_aio_poll(void *opaque)
{
EventNotifier *n = opaque;
VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
bool progress;
if (!vq->vring.desc || virtio_queue_empty(vq)) {
return false;
}
progress = virtio_queue_notify_aio_vq(vq);
namely the call to virtio_queue_empty(). In this case, since no new
requests have actually been issued, shadow_avail_idx == last_avail_idx,
so we actually try to access the vring via vring_avail_idx() to get
the latest non-shadowed idx:
int virtio_queue_empty(VirtQueue *vq)
{
bool empty;
...
if (vq->shadow_avail_idx != vq->last_avail_idx) {
return 0;
}
rcu_read_lock();
empty = vring_avail_idx(vq) == vq->last_avail_idx;
rcu_read_unlock();
return empty;
but since the IOMMU region has been disabled we get a bogus value (0
usually), which causes virtio_queue_empty() to falsely report that
there are entries to be processed, which causes errors such as:
"virtio: zero sized buffers are not allowed"
or
"virtio-blk missing headers"
and puts the device in an error state.
This patch works around the issue by introducing virtio_set_disabled(),
which sets a 'disabled' flag to bypass checks like virtio_queue_empty()
when bus-mastering is disabled. Since we'd check this flag at all the
same sites as vdev->broken, we replace those checks with an inline
function which checks for either vdev->broken or vdev->disabled.
The 'disabled' flag is only migrated when set, which should be fairly
rare, but to maintain migration compatibility we disable it's use for
older machine types. Users requiring the use of the flag in conjunction
with older machine types can set it explicitly as a virtio-device
option.
NOTES:
- This leaves some other oddities in play, like the fact that
DRIVER_OK also gets unset in response to bus-mastering being
disabled, but not restored (however the device seems to continue
working)
- Similarly, we disable the host notifier via
virtio_bus_stop_ioeventfd(), which seems to move the handling out
of virtio-blk dataplane and back into the main IO thread, and it
ends up staying there till a reset (but otherwise continues working
normally)
Cc: David Gibson <david@gibson.dropbear.id.au>,
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Message-Id: <20191120005003.27035-1-mdroth@linux.vnet.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-11-20 01:50:03 +01:00
|
|
|
{ "virtio-device", "use-disabled-flag", "false" },
|
2019-08-20 18:30:05 +02:00
|
|
|
};
|
2019-07-24 12:35:24 +02:00
|
|
|
const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1);
|
|
|
|
|
2019-06-14 15:09:02 +02:00
|
|
|
GlobalProperty hw_compat_4_0[] = {
|
2019-06-07 10:34:44 +02:00
|
|
|
{ "VGA", "edid", "false" },
|
|
|
|
{ "secondary-vga", "edid", "false" },
|
|
|
|
{ "bochs-display", "edid", "false" },
|
|
|
|
{ "virtio-vga", "edid", "false" },
|
2019-08-06 13:58:19 +02:00
|
|
|
{ "virtio-gpu", "edid", "false" },
|
2019-06-26 04:31:26 +02:00
|
|
|
{ "virtio-device", "use-started", "false" },
|
2019-07-10 16:14:40 +02:00
|
|
|
{ "virtio-balloon-device", "qemu-4-0-config-size", "true" },
|
2019-07-15 15:17:04 +02:00
|
|
|
{ "pl031", "migrate-tick-offset", "false" },
|
2019-06-07 10:34:44 +02:00
|
|
|
};
|
2019-04-11 12:20:25 +02:00
|
|
|
const size_t hw_compat_4_0_len = G_N_ELEMENTS(hw_compat_4_0);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_3_1[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "pcie-root-port", "x-speed", "2_5" },
|
|
|
|
{ "pcie-root-port", "x-width", "1" },
|
|
|
|
{ "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" },
|
|
|
|
{ "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" },
|
2019-01-14 23:27:49 +01:00
|
|
|
{ "tpm-crb", "ppi", "false" },
|
|
|
|
{ "tpm-tis", "ppi", "false" },
|
2019-01-10 13:51:08 +01:00
|
|
|
{ "usb-kbd", "serial", "42" },
|
|
|
|
{ "usb-mouse", "serial", "42" },
|
2019-05-20 10:18:05 +02:00
|
|
|
{ "usb-tablet", "serial", "42" },
|
2019-02-21 11:33:07 +01:00
|
|
|
{ "virtio-blk-device", "discard", "false" },
|
|
|
|
{ "virtio-blk-device", "write-zeroes", "false" },
|
2019-07-10 16:14:40 +02:00
|
|
|
{ "virtio-balloon-device", "qemu-4-0-config-size", "false" },
|
2019-07-30 11:37:19 +02:00
|
|
|
{ "pcie-root-port-base", "disable-acs", "true" }, /* Added in 4.1 */
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_3_0[] = {};
|
|
|
|
const size_t hw_compat_3_0_len = G_N_ELEMENTS(hw_compat_3_0);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_12[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "migration", "decompress-error-check", "off" },
|
|
|
|
{ "hda-audio", "use-timer", "false" },
|
|
|
|
{ "cirrus-vga", "global-vmstate", "true" },
|
|
|
|
{ "VGA", "global-vmstate", "true" },
|
|
|
|
{ "vmware-svga", "global-vmstate", "true" },
|
|
|
|
{ "qxl-vga", "global-vmstate", "true" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_12_len = G_N_ELEMENTS(hw_compat_2_12);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_11[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "hpet", "hpet-offset-saved", "false" },
|
|
|
|
{ "virtio-blk-pci", "vectors", "2" },
|
|
|
|
{ "vhost-user-blk-pci", "vectors", "2" },
|
|
|
|
{ "e1000", "migrate_tso_props", "off" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_11_len = G_N_ELEMENTS(hw_compat_2_11);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_10[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "virtio-mouse-device", "wheel-axis", "false" },
|
|
|
|
{ "virtio-tablet-device", "wheel-axis", "false" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_10_len = G_N_ELEMENTS(hw_compat_2_10);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_9[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "pci-bridge", "shpc", "off" },
|
|
|
|
{ "intel-iommu", "pt", "off" },
|
|
|
|
{ "virtio-net-device", "x-mtu-bypass-backend", "off" },
|
|
|
|
{ "pcie-root-port", "x-migrate-msix", "false" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_9_len = G_N_ELEMENTS(hw_compat_2_9);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_8[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "fw_cfg_mem", "x-file-slots", "0x10" },
|
|
|
|
{ "fw_cfg_io", "x-file-slots", "0x10" },
|
|
|
|
{ "pflash_cfi01", "old-multiple-chip-handling", "on" },
|
|
|
|
{ "pci-bridge", "shpc", "on" },
|
|
|
|
{ TYPE_PCI_DEVICE, "x-pcie-extcap-init", "off" },
|
|
|
|
{ "virtio-pci", "x-pcie-deverr-init", "off" },
|
|
|
|
{ "virtio-pci", "x-pcie-lnkctl-init", "off" },
|
|
|
|
{ "virtio-pci", "x-pcie-pm-init", "off" },
|
|
|
|
{ "cirrus-vga", "vgamem_mb", "8" },
|
|
|
|
{ "isa-cirrus-vga", "vgamem_mb", "8" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_8_len = G_N_ELEMENTS(hw_compat_2_8);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_7[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "virtio-pci", "page-per-vq", "on" },
|
|
|
|
{ "virtio-serial-device", "emergency-write", "off" },
|
|
|
|
{ "ioapic", "version", "0x11" },
|
|
|
|
{ "intel-iommu", "x-buggy-eim", "true" },
|
|
|
|
{ "virtio-pci", "x-ignore-backend-features", "on" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_6[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "virtio-mmio", "format_transport_address", "off" },
|
2019-07-29 18:29:03 +02:00
|
|
|
/* Optional because not all virtio-pci devices support legacy mode */
|
|
|
|
{ "virtio-pci", "disable-modern", "on", .optional = true },
|
|
|
|
{ "virtio-pci", "disable-legacy", "off", .optional = true },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_5[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "isa-fdc", "fallback", "144" },
|
|
|
|
{ "pvscsi", "x-old-pci-configuration", "on" },
|
|
|
|
{ "pvscsi", "x-disable-pcie", "on" },
|
|
|
|
{ "vmxnet3", "x-old-msi-offsets", "on" },
|
|
|
|
{ "vmxnet3", "x-disable-pcie", "on" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_5_len = G_N_ELEMENTS(hw_compat_2_5);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_4[] = {
|
2020-02-07 01:14:04 +01:00
|
|
|
/* Optional because the 'scsi' property is Linux-only */
|
|
|
|
{ "virtio-blk-device", "scsi", "true", .optional = true },
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "e1000", "extra_mac_registers", "off" },
|
|
|
|
{ "virtio-pci", "x-disable-pcie", "on" },
|
|
|
|
{ "virtio-pci", "migrate-extra", "off" },
|
|
|
|
{ "fw_cfg_mem", "dma_enabled", "off" },
|
|
|
|
{ "fw_cfg_io", "dma_enabled", "off" }
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_4_len = G_N_ELEMENTS(hw_compat_2_4);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_3[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "virtio-blk-pci", "any_layout", "off" },
|
|
|
|
{ "virtio-balloon-pci", "any_layout", "off" },
|
|
|
|
{ "virtio-serial-pci", "any_layout", "off" },
|
|
|
|
{ "virtio-9p-pci", "any_layout", "off" },
|
|
|
|
{ "virtio-rng-pci", "any_layout", "off" },
|
|
|
|
{ TYPE_PCI_DEVICE, "x-pcie-lnksta-dllla", "off" },
|
|
|
|
{ "migration", "send-configuration", "off" },
|
|
|
|
{ "migration", "send-section-footer", "off" },
|
|
|
|
{ "migration", "store-global-state", "off" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_3_len = G_N_ELEMENTS(hw_compat_2_3);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_2[] = {};
|
|
|
|
const size_t hw_compat_2_2_len = G_N_ELEMENTS(hw_compat_2_2);
|
|
|
|
|
2018-12-12 16:36:30 +01:00
|
|
|
GlobalProperty hw_compat_2_1[] = {
|
2019-01-07 20:30:20 +01:00
|
|
|
{ "intel-hda", "old_msi_addr", "on" },
|
|
|
|
{ "VGA", "qemu-extended-regs", "off" },
|
|
|
|
{ "secondary-vga", "qemu-extended-regs", "off" },
|
|
|
|
{ "virtio-scsi-pci", "any_layout", "off" },
|
|
|
|
{ "usb-mouse", "usb_version", "1" },
|
|
|
|
{ "usb-kbd", "usb_version", "1" },
|
|
|
|
{ "virtio-pci", "virtio-pci-bus-master-bug-migration", "on" },
|
2018-12-12 16:36:30 +01:00
|
|
|
};
|
|
|
|
const size_t hw_compat_2_1_len = G_N_ELEMENTS(hw_compat_2_1);
|
|
|
|
|
2014-05-26 14:40:58 +02:00
|
|
|
static char *machine_get_kernel(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->kernel_filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_kernel(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2014-08-06 20:18:21 +02:00
|
|
|
g_free(ms->kernel_filename);
|
2014-05-26 14:40:58 +02:00
|
|
|
ms->kernel_filename = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *machine_get_initrd(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->initrd_filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_initrd(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2014-08-06 20:18:21 +02:00
|
|
|
g_free(ms->initrd_filename);
|
2014-05-26 14:40:58 +02:00
|
|
|
ms->initrd_filename = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *machine_get_append(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->kernel_cmdline);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_append(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2014-08-06 20:18:21 +02:00
|
|
|
g_free(ms->kernel_cmdline);
|
2014-05-26 14:40:58 +02:00
|
|
|
ms->kernel_cmdline = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *machine_get_dtb(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->dtb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_dtb(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2014-08-06 20:18:21 +02:00
|
|
|
g_free(ms->dtb);
|
2014-05-26 14:40:58 +02:00
|
|
|
ms->dtb = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *machine_get_dumpdtb(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->dumpdtb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2014-08-06 20:18:21 +02:00
|
|
|
g_free(ms->dumpdtb);
|
2014-05-26 14:40:58 +02:00
|
|
|
ms->dumpdtb = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_get_phandle_start(Object *obj, Visitor *v,
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 14:48:55 +01:00
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2014-05-26 14:40:58 +02:00
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
int64_t value = ms->phandle_start;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 14:48:54 +01:00
|
|
|
visit_type_int(v, name, &value, errp);
|
2014-05-26 14:40:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_phandle_start(Object *obj, Visitor *v,
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 14:48:55 +01:00
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2014-05-26 14:40:58 +02:00
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
Error *error = NULL;
|
|
|
|
int64_t value;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 14:48:54 +01:00
|
|
|
visit_type_int(v, name, &value, &error);
|
2014-05-26 14:40:58 +02:00
|
|
|
if (error) {
|
|
|
|
error_propagate(errp, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ms->phandle_start = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *machine_get_dt_compatible(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->dt_compatible);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2014-08-06 20:18:21 +02:00
|
|
|
g_free(ms->dt_compatible);
|
2014-05-26 14:40:58 +02:00
|
|
|
ms->dt_compatible = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool machine_get_dump_guest_core(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->dump_guest_core;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
ms->dump_guest_core = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool machine_get_mem_merge(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->mem_merge;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_mem_merge(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
ms->mem_merge = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool machine_get_usb(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->usb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_usb(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
ms->usb = value;
|
2015-03-23 18:05:28 +01:00
|
|
|
ms->usb_disabled = !value;
|
2014-05-26 14:40:58 +02:00
|
|
|
}
|
|
|
|
|
2016-04-19 21:55:25 +02:00
|
|
|
static bool machine_get_graphics(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->enable_graphics;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_graphics(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
ms->enable_graphics = value;
|
|
|
|
}
|
|
|
|
|
2014-05-26 14:40:58 +02:00
|
|
|
static char *machine_get_firmware(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->firmware);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_firmware(Object *obj, const char *value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2014-08-06 20:18:21 +02:00
|
|
|
g_free(ms->firmware);
|
2014-05-26 14:40:58 +02:00
|
|
|
ms->firmware = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
2015-02-23 13:56:42 +01:00
|
|
|
static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
ms->suppress_vmdesc = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool machine_get_suppress_vmdesc(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->suppress_vmdesc;
|
|
|
|
}
|
|
|
|
|
2016-02-18 12:32:25 +01:00
|
|
|
static void machine_set_enforce_config_section(Object *obj, bool value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
2018-09-20 09:22:07 +02:00
|
|
|
warn_report("enforce-config-section is deprecated, please use "
|
|
|
|
"-global migration.send-configuration=on|off instead");
|
|
|
|
|
2016-02-18 12:32:25 +01:00
|
|
|
ms->enforce_config_section = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool machine_get_enforce_config_section(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->enforce_config_section;
|
|
|
|
}
|
|
|
|
|
2018-03-08 13:48:38 +01:00
|
|
|
static char *machine_get_memory_encryption(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->memory_encryption);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_memory_encryption(Object *obj, const char *value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
g_free(ms->memory_encryption);
|
|
|
|
ms->memory_encryption = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
2019-03-08 19:20:53 +01:00
|
|
|
static bool machine_get_nvdimm(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->nvdimms_state->is_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_nvdimm(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
ms->nvdimms_state->is_enabled = value;
|
|
|
|
}
|
|
|
|
|
2019-12-13 02:19:22 +01:00
|
|
|
static bool machine_get_hmat(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return ms->numa_state->hmat_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_hmat(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
ms->numa_state->hmat_enabled = value;
|
|
|
|
}
|
|
|
|
|
2019-03-08 19:20:53 +01:00
|
|
|
static char *machine_get_nvdimm_persistence(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
return g_strdup(ms->nvdimms_state->persistence_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_set_nvdimm_persistence(Object *obj, const char *value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
NVDIMMState *nvdimms_state = ms->nvdimms_state;
|
|
|
|
|
|
|
|
if (strcmp(value, "cpu") == 0) {
|
|
|
|
nvdimms_state->persistence = 3;
|
|
|
|
} else if (strcmp(value, "mem-ctrl") == 0) {
|
|
|
|
nvdimms_state->persistence = 2;
|
|
|
|
} else {
|
|
|
|
error_setg(errp, "-machine nvdimm-persistence=%s: unsupported option",
|
|
|
|
value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(nvdimms_state->persistence_string);
|
|
|
|
nvdimms_state->persistence_string = g_strdup(value);
|
|
|
|
}
|
|
|
|
|
2017-11-25 16:16:05 +01:00
|
|
|
void machine_class_allow_dynamic_sysbus_dev(MachineClass *mc, const char *type)
|
2014-07-01 16:14:41 +02:00
|
|
|
{
|
2017-11-25 16:16:05 +01:00
|
|
|
strList *item = g_new0(strList, 1);
|
|
|
|
|
|
|
|
item->value = g_strdup(type);
|
|
|
|
item->next = mc->allowed_dynamic_sysbus_devices;
|
|
|
|
mc->allowed_dynamic_sysbus_devices = item;
|
2014-07-01 16:14:41 +02:00
|
|
|
}
|
|
|
|
|
2017-11-25 16:16:05 +01:00
|
|
|
static void validate_sysbus_device(SysBusDevice *sbdev, void *opaque)
|
2014-07-01 16:14:41 +02:00
|
|
|
{
|
2017-11-25 16:16:05 +01:00
|
|
|
MachineState *machine = opaque;
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
|
|
|
bool allowed = false;
|
|
|
|
strList *wl;
|
2014-07-01 16:14:41 +02:00
|
|
|
|
2017-11-25 16:16:05 +01:00
|
|
|
for (wl = mc->allowed_dynamic_sysbus_devices;
|
|
|
|
!allowed && wl;
|
|
|
|
wl = wl->next) {
|
|
|
|
allowed |= !!object_dynamic_cast(OBJECT(sbdev), wl->value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!allowed) {
|
|
|
|
error_report("Option '-device %s' cannot be handled by this machine",
|
|
|
|
object_class_get_name(object_get_class(OBJECT(sbdev))));
|
|
|
|
exit(1);
|
2014-07-01 16:14:41 +02:00
|
|
|
}
|
2017-11-25 16:16:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_init_notify(Notifier *notifier, void *data)
|
|
|
|
{
|
|
|
|
MachineState *machine = MACHINE(qdev_get_machine());
|
2014-07-01 16:14:41 +02:00
|
|
|
|
|
|
|
/*
|
2017-11-25 16:16:05 +01:00
|
|
|
* Loop through all dynamically created sysbus devices and check if they are
|
|
|
|
* all allowed. If a device is not allowed, error out.
|
2014-07-01 16:14:41 +02:00
|
|
|
*/
|
2017-11-25 16:16:05 +01:00
|
|
|
foreach_dynamic_sysbus_device(validate_sysbus_device, machine);
|
2014-07-01 16:14:41 +02:00
|
|
|
}
|
|
|
|
|
2017-02-09 12:08:38 +01:00
|
|
|
HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
HotpluggableCPUList *head = NULL;
|
2018-01-10 16:22:50 +01:00
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
|
|
|
|
|
|
|
/* force board to initialize possible_cpus if it hasn't been done yet */
|
|
|
|
mc->possible_cpu_arch_ids(machine);
|
2017-02-09 12:08:38 +01:00
|
|
|
|
|
|
|
for (i = 0; i < machine->possible_cpus->len; i++) {
|
2018-01-10 16:22:50 +01:00
|
|
|
Object *cpu;
|
2017-02-09 12:08:38 +01:00
|
|
|
HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1);
|
|
|
|
HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1);
|
|
|
|
|
2018-01-10 16:22:50 +01:00
|
|
|
cpu_item->type = g_strdup(machine->possible_cpus->cpus[i].type);
|
2017-02-09 12:08:38 +01:00
|
|
|
cpu_item->vcpus_count = machine->possible_cpus->cpus[i].vcpus_count;
|
|
|
|
cpu_item->props = g_memdup(&machine->possible_cpus->cpus[i].props,
|
|
|
|
sizeof(*cpu_item->props));
|
|
|
|
|
|
|
|
cpu = machine->possible_cpus->cpus[i].cpu;
|
|
|
|
if (cpu) {
|
|
|
|
cpu_item->has_qom_path = true;
|
|
|
|
cpu_item->qom_path = object_get_canonical_path(cpu);
|
|
|
|
}
|
|
|
|
list_item->value = cpu_item;
|
|
|
|
list_item->next = head;
|
|
|
|
head = list_item;
|
|
|
|
}
|
|
|
|
return head;
|
|
|
|
}
|
|
|
|
|
2017-05-10 13:29:50 +02:00
|
|
|
/**
|
|
|
|
* machine_set_cpu_numa_node:
|
|
|
|
* @machine: machine object to modify
|
|
|
|
* @props: specifies which cpu objects to assign to
|
|
|
|
* numa node specified by @props.node_id
|
|
|
|
* @errp: if an error occurs, a pointer to an area to store the error
|
|
|
|
*
|
|
|
|
* Associate NUMA node specified by @props.node_id with cpu slots that
|
|
|
|
* match socket/core/thread-ids specified by @props. It's recommended to use
|
|
|
|
* query-hotpluggable-cpus.props values to specify affected cpu slots,
|
|
|
|
* which would lead to exact 1:1 mapping of cpu slots to NUMA node.
|
|
|
|
*
|
|
|
|
* However for CLI convenience it's possible to pass in subset of properties,
|
|
|
|
* which would affect all cpu slots that match it.
|
|
|
|
* Ex for pc machine:
|
|
|
|
* -smp 4,cores=2,sockets=2 -numa node,nodeid=0 -numa node,nodeid=1 \
|
|
|
|
* -numa cpu,node-id=0,socket_id=0 \
|
|
|
|
* -numa cpu,node-id=1,socket_id=1
|
|
|
|
* will assign all child cores of socket 0 to node 0 and
|
|
|
|
* of socket 1 to node 1.
|
|
|
|
*
|
|
|
|
* On attempt of reassigning (already assigned) cpu slot to another NUMA node,
|
|
|
|
* return error.
|
|
|
|
* Empty subset is disallowed and function will return with error in this case.
|
|
|
|
*/
|
|
|
|
void machine_set_cpu_numa_node(MachineState *machine,
|
|
|
|
const CpuInstanceProperties *props, Error **errp)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
2019-12-13 02:19:22 +01:00
|
|
|
NodeInfo *numa_info = machine->numa_state->nodes;
|
2017-05-10 13:29:50 +02:00
|
|
|
bool match = false;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!mc->possible_cpu_arch_ids) {
|
|
|
|
error_setg(errp, "mapping of CPUs to NUMA node is not supported");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disabling node mapping is not supported, forbid it */
|
|
|
|
assert(props->has_node_id);
|
|
|
|
|
|
|
|
/* force board to initialize possible_cpus if it hasn't been done yet */
|
|
|
|
mc->possible_cpu_arch_ids(machine);
|
|
|
|
|
|
|
|
for (i = 0; i < machine->possible_cpus->len; i++) {
|
|
|
|
CPUArchId *slot = &machine->possible_cpus->cpus[i];
|
|
|
|
|
|
|
|
/* reject unsupported by board properties */
|
|
|
|
if (props->has_thread_id && !slot->props.has_thread_id) {
|
|
|
|
error_setg(errp, "thread-id is not supported");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (props->has_core_id && !slot->props.has_core_id) {
|
|
|
|
error_setg(errp, "core-id is not supported");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (props->has_socket_id && !slot->props.has_socket_id) {
|
|
|
|
error_setg(errp, "socket-id is not supported");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-12 10:40:58 +02:00
|
|
|
if (props->has_die_id && !slot->props.has_die_id) {
|
|
|
|
error_setg(errp, "die-id is not supported");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-10 13:29:50 +02:00
|
|
|
/* skip slots with explicit mismatch */
|
|
|
|
if (props->has_thread_id && props->thread_id != slot->props.thread_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (props->has_core_id && props->core_id != slot->props.core_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-06-12 10:40:58 +02:00
|
|
|
if (props->has_die_id && props->die_id != slot->props.die_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-05-10 13:29:50 +02:00
|
|
|
if (props->has_socket_id && props->socket_id != slot->props.socket_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reject assignment if slot is already assigned, for compatibility
|
|
|
|
* of legacy cpu_index mapping with SPAPR core based mapping do not
|
|
|
|
* error out if cpu thread and matched core have the same node-id */
|
|
|
|
if (slot->props.has_node_id &&
|
|
|
|
slot->props.node_id != props->node_id) {
|
|
|
|
error_setg(errp, "CPU is already assigned to node-id: %" PRId64,
|
|
|
|
slot->props.node_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* assign slot to node as it's matched '-numa cpu' key */
|
|
|
|
match = true;
|
|
|
|
slot->props.node_id = props->node_id;
|
|
|
|
slot->props.has_node_id = props->has_node_id;
|
2019-12-13 02:19:22 +01:00
|
|
|
|
|
|
|
if (machine->numa_state->hmat_enabled) {
|
|
|
|
if ((numa_info[props->node_id].initiator < MAX_NODES) &&
|
|
|
|
(props->node_id != numa_info[props->node_id].initiator)) {
|
|
|
|
error_setg(errp, "The initiator of CPU NUMA node %" PRId64
|
|
|
|
" should be itself", props->node_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
numa_info[props->node_id].has_cpu = true;
|
|
|
|
numa_info[props->node_id].initiator = props->node_id;
|
|
|
|
}
|
2017-05-10 13:29:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
error_setg(errp, "no match found");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-20 07:45:24 +02:00
|
|
|
static void smp_parse(MachineState *ms, QemuOpts *opts)
|
|
|
|
{
|
|
|
|
if (opts) {
|
|
|
|
unsigned cpus = qemu_opt_get_number(opts, "cpus", 0);
|
|
|
|
unsigned sockets = qemu_opt_get_number(opts, "sockets", 0);
|
|
|
|
unsigned cores = qemu_opt_get_number(opts, "cores", 0);
|
|
|
|
unsigned threads = qemu_opt_get_number(opts, "threads", 0);
|
|
|
|
|
|
|
|
/* compute missing values, prefer sockets over cores over threads */
|
|
|
|
if (cpus == 0 || sockets == 0) {
|
|
|
|
cores = cores > 0 ? cores : 1;
|
|
|
|
threads = threads > 0 ? threads : 1;
|
|
|
|
if (cpus == 0) {
|
|
|
|
sockets = sockets > 0 ? sockets : 1;
|
|
|
|
cpus = cores * threads * sockets;
|
|
|
|
} else {
|
|
|
|
ms->smp.max_cpus =
|
|
|
|
qemu_opt_get_number(opts, "maxcpus", cpus);
|
|
|
|
sockets = ms->smp.max_cpus / (cores * threads);
|
|
|
|
}
|
|
|
|
} else if (cores == 0) {
|
|
|
|
threads = threads > 0 ? threads : 1;
|
|
|
|
cores = cpus / (sockets * threads);
|
|
|
|
cores = cores > 0 ? cores : 1;
|
|
|
|
} else if (threads == 0) {
|
|
|
|
threads = cpus / (cores * sockets);
|
|
|
|
threads = threads > 0 ? threads : 1;
|
|
|
|
} else if (sockets * cores * threads < cpus) {
|
|
|
|
error_report("cpu topology: "
|
|
|
|
"sockets (%u) * cores (%u) * threads (%u) < "
|
|
|
|
"smp_cpus (%u)",
|
|
|
|
sockets, cores, threads, cpus);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ms->smp.max_cpus =
|
|
|
|
qemu_opt_get_number(opts, "maxcpus", cpus);
|
|
|
|
|
|
|
|
if (ms->smp.max_cpus < cpus) {
|
|
|
|
error_report("maxcpus must be equal to or greater than smp");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sockets * cores * threads > ms->smp.max_cpus) {
|
|
|
|
error_report("cpu topology: "
|
|
|
|
"sockets (%u) * cores (%u) * threads (%u) > "
|
|
|
|
"maxcpus (%u)",
|
|
|
|
sockets, cores, threads,
|
|
|
|
ms->smp.max_cpus);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sockets * cores * threads != ms->smp.max_cpus) {
|
|
|
|
warn_report("Invalid CPU topology deprecated: "
|
|
|
|
"sockets (%u) * cores (%u) * threads (%u) "
|
|
|
|
"!= maxcpus (%u)",
|
|
|
|
sockets, cores, threads,
|
|
|
|
ms->smp.max_cpus);
|
|
|
|
}
|
|
|
|
|
|
|
|
ms->smp.cpus = cpus;
|
|
|
|
ms->smp.cores = cores;
|
|
|
|
ms->smp.threads = threads;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ms->smp.cpus > 1) {
|
|
|
|
Error *blocker = NULL;
|
|
|
|
error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp");
|
|
|
|
replay_add_blocker(blocker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-07 07:33:57 +02:00
|
|
|
static void machine_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
|
|
|
|
|
|
|
/* Default 128 MB as guest ram size */
|
2018-06-25 14:41:57 +02:00
|
|
|
mc->default_ram_size = 128 * MiB;
|
2015-12-01 23:58:08 +01:00
|
|
|
mc->rom_file_has_mr = true;
|
2019-06-20 07:45:24 +02:00
|
|
|
mc->smp_parse = smp_parse;
|
2016-10-13 22:40:46 +02:00
|
|
|
|
2017-03-21 11:25:42 +01:00
|
|
|
/* numa node memory size aligned on 8MB by default.
|
|
|
|
* On Linux, each node's border has to be 8MB aligned
|
|
|
|
*/
|
|
|
|
mc->numa_mem_align_shift = 23;
|
2017-05-02 18:29:55 +02:00
|
|
|
mc->numa_auto_assign_ram = numa_default_auto_assign_ram;
|
2017-03-21 11:25:42 +01:00
|
|
|
|
2016-10-13 22:40:46 +02:00
|
|
|
object_class_property_add_str(oc, "kernel",
|
|
|
|
machine_get_kernel, machine_set_kernel, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "kernel",
|
|
|
|
"Linux kernel image file", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_str(oc, "initrd",
|
|
|
|
machine_get_initrd, machine_set_initrd, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "initrd",
|
|
|
|
"Linux initial ramdisk file", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_str(oc, "append",
|
|
|
|
machine_get_append, machine_set_append, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "append",
|
|
|
|
"Linux kernel command line", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_str(oc, "dtb",
|
|
|
|
machine_get_dtb, machine_set_dtb, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "dtb",
|
|
|
|
"Linux kernel device tree file", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_str(oc, "dumpdtb",
|
|
|
|
machine_get_dumpdtb, machine_set_dumpdtb, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "dumpdtb",
|
|
|
|
"Dump current dtb to a file and quit", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add(oc, "phandle-start", "int",
|
|
|
|
machine_get_phandle_start, machine_set_phandle_start,
|
|
|
|
NULL, NULL, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "phandle-start",
|
|
|
|
"The first phandle ID we may generate dynamically", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_str(oc, "dt-compatible",
|
|
|
|
machine_get_dt_compatible, machine_set_dt_compatible, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "dt-compatible",
|
|
|
|
"Overrides the \"compatible\" property of the dt root node",
|
|
|
|
&error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "dump-guest-core",
|
|
|
|
machine_get_dump_guest_core, machine_set_dump_guest_core, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "dump-guest-core",
|
2018-12-24 16:49:22 +01:00
|
|
|
"Include guest memory in a core dump", &error_abort);
|
2016-10-13 22:40:46 +02:00
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "mem-merge",
|
|
|
|
machine_get_mem_merge, machine_set_mem_merge, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "mem-merge",
|
|
|
|
"Enable/disable memory merge support", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "usb",
|
|
|
|
machine_get_usb, machine_set_usb, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "usb",
|
|
|
|
"Set on/off to enable/disable usb", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "graphics",
|
|
|
|
machine_get_graphics, machine_set_graphics, &error_abort);
|
|
|
|
object_class_property_set_description(oc, "graphics",
|
|
|
|
"Set on/off to enable/disable graphics emulation", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_str(oc, "firmware",
|
|
|
|
machine_get_firmware, machine_set_firmware,
|
|
|
|
&error_abort);
|
|
|
|
object_class_property_set_description(oc, "firmware",
|
|
|
|
"Firmware image", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "suppress-vmdesc",
|
|
|
|
machine_get_suppress_vmdesc, machine_set_suppress_vmdesc,
|
|
|
|
&error_abort);
|
|
|
|
object_class_property_set_description(oc, "suppress-vmdesc",
|
|
|
|
"Set on to disable self-describing migration", &error_abort);
|
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "enforce-config-section",
|
|
|
|
machine_get_enforce_config_section, machine_set_enforce_config_section,
|
|
|
|
&error_abort);
|
|
|
|
object_class_property_set_description(oc, "enforce-config-section",
|
|
|
|
"Set on to enforce configuration section migration", &error_abort);
|
2018-03-08 13:48:38 +01:00
|
|
|
|
|
|
|
object_class_property_add_str(oc, "memory-encryption",
|
|
|
|
machine_get_memory_encryption, machine_set_memory_encryption,
|
|
|
|
&error_abort);
|
|
|
|
object_class_property_set_description(oc, "memory-encryption",
|
2018-10-10 18:10:25 +02:00
|
|
|
"Set memory encryption object to use", &error_abort);
|
2015-05-07 07:33:57 +02:00
|
|
|
}
|
|
|
|
|
2015-08-20 23:54:35 +02:00
|
|
|
static void machine_class_base_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
if (!object_class_is_abstract(oc)) {
|
2015-08-20 23:54:36 +02:00
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
2015-08-20 23:54:35 +02:00
|
|
|
const char *cname = object_class_get_name(oc);
|
|
|
|
assert(g_str_has_suffix(cname, TYPE_MACHINE_SUFFIX));
|
2015-08-20 23:54:36 +02:00
|
|
|
mc->name = g_strndup(cname,
|
|
|
|
strlen(cname) - strlen(TYPE_MACHINE_SUFFIX));
|
2018-12-01 20:44:11 +01:00
|
|
|
mc->compat_props = g_ptr_array_new();
|
2015-08-20 23:54:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-26 14:40:58 +02:00
|
|
|
static void machine_initfn(Object *obj)
|
|
|
|
{
|
2014-07-01 16:14:41 +02:00
|
|
|
MachineState *ms = MACHINE(obj);
|
2018-12-20 06:40:35 +01:00
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
2014-07-01 16:14:41 +02:00
|
|
|
|
2015-02-04 16:43:54 +01:00
|
|
|
ms->dump_guest_core = true;
|
2015-02-04 16:43:55 +01:00
|
|
|
ms->mem_merge = true;
|
2016-04-19 21:55:25 +02:00
|
|
|
ms->enable_graphics = true;
|
2015-02-04 16:43:49 +01:00
|
|
|
|
2019-03-08 19:20:53 +01:00
|
|
|
if (mc->nvdimm_supported) {
|
|
|
|
Object *obj = OBJECT(ms);
|
|
|
|
|
|
|
|
ms->nvdimms_state = g_new0(NVDIMMState, 1);
|
|
|
|
object_property_add_bool(obj, "nvdimm",
|
|
|
|
machine_get_nvdimm, machine_set_nvdimm,
|
|
|
|
&error_abort);
|
|
|
|
object_property_set_description(obj, "nvdimm",
|
|
|
|
"Set on/off to enable/disable "
|
|
|
|
"NVDIMM instantiation", NULL);
|
|
|
|
|
|
|
|
object_property_add_str(obj, "nvdimm-persistence",
|
|
|
|
machine_get_nvdimm_persistence,
|
|
|
|
machine_set_nvdimm_persistence,
|
|
|
|
&error_abort);
|
|
|
|
object_property_set_description(obj, "nvdimm-persistence",
|
|
|
|
"Set NVDIMM persistence"
|
|
|
|
"Valid values are cpu, mem-ctrl",
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2019-12-12 13:48:56 +01:00
|
|
|
if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) {
|
2019-08-09 08:57:22 +02:00
|
|
|
ms->numa_state = g_new0(NumaState, 1);
|
2019-12-13 02:19:22 +01:00
|
|
|
object_property_add_bool(obj, "hmat",
|
|
|
|
machine_get_hmat, machine_set_hmat,
|
|
|
|
&error_abort);
|
|
|
|
object_property_set_description(obj, "hmat",
|
|
|
|
"Set on/off to enable/disable "
|
|
|
|
"ACPI Heterogeneous Memory Attribute "
|
|
|
|
"Table (HMAT)", NULL);
|
2019-08-09 08:57:22 +02:00
|
|
|
}
|
2019-03-08 19:20:53 +01:00
|
|
|
|
2014-07-01 16:14:41 +02:00
|
|
|
/* Register notifier when init is done for sysbus sanity checks */
|
|
|
|
ms->sysbus_notifier.notify = machine_init_notify;
|
|
|
|
qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
|
2014-05-26 14:40:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void machine_finalize(Object *obj)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(obj);
|
|
|
|
|
|
|
|
g_free(ms->kernel_filename);
|
|
|
|
g_free(ms->initrd_filename);
|
|
|
|
g_free(ms->kernel_cmdline);
|
|
|
|
g_free(ms->dtb);
|
|
|
|
g_free(ms->dumpdtb);
|
|
|
|
g_free(ms->dt_compatible);
|
|
|
|
g_free(ms->firmware);
|
2018-07-02 11:41:52 +02:00
|
|
|
g_free(ms->device_memory);
|
2019-03-08 19:20:53 +01:00
|
|
|
g_free(ms->nvdimms_state);
|
2019-08-09 08:57:22 +02:00
|
|
|
g_free(ms->numa_state);
|
2014-05-26 14:40:58 +02:00
|
|
|
}
|
2014-03-05 18:30:45 +01:00
|
|
|
|
2015-01-06 14:29:13 +01:00
|
|
|
bool machine_usb(MachineState *machine)
|
|
|
|
{
|
|
|
|
return machine->usb;
|
|
|
|
}
|
|
|
|
|
2015-02-04 16:43:53 +01:00
|
|
|
int machine_phandle_start(MachineState *machine)
|
|
|
|
{
|
|
|
|
return machine->phandle_start;
|
|
|
|
}
|
|
|
|
|
2015-02-04 16:43:54 +01:00
|
|
|
bool machine_dump_guest_core(MachineState *machine)
|
|
|
|
{
|
|
|
|
return machine->dump_guest_core;
|
|
|
|
}
|
|
|
|
|
2015-02-04 16:43:55 +01:00
|
|
|
bool machine_mem_merge(MachineState *machine)
|
|
|
|
{
|
|
|
|
return machine->mem_merge;
|
|
|
|
}
|
|
|
|
|
2017-05-10 13:29:59 +02:00
|
|
|
static char *cpu_slot_to_string(const CPUArchId *cpu)
|
|
|
|
{
|
|
|
|
GString *s = g_string_new(NULL);
|
|
|
|
if (cpu->props.has_socket_id) {
|
|
|
|
g_string_append_printf(s, "socket-id: %"PRId64, cpu->props.socket_id);
|
|
|
|
}
|
2019-06-12 10:40:58 +02:00
|
|
|
if (cpu->props.has_die_id) {
|
|
|
|
g_string_append_printf(s, "die-id: %"PRId64, cpu->props.die_id);
|
|
|
|
}
|
2017-05-10 13:29:59 +02:00
|
|
|
if (cpu->props.has_core_id) {
|
|
|
|
if (s->len) {
|
|
|
|
g_string_append_printf(s, ", ");
|
|
|
|
}
|
|
|
|
g_string_append_printf(s, "core-id: %"PRId64, cpu->props.core_id);
|
|
|
|
}
|
|
|
|
if (cpu->props.has_thread_id) {
|
|
|
|
if (s->len) {
|
|
|
|
g_string_append_printf(s, ", ");
|
|
|
|
}
|
|
|
|
g_string_append_printf(s, "thread-id: %"PRId64, cpu->props.thread_id);
|
|
|
|
}
|
|
|
|
return g_string_free(s, false);
|
|
|
|
}
|
|
|
|
|
2019-12-13 02:19:22 +01:00
|
|
|
static void numa_validate_initiator(NumaState *numa_state)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
NodeInfo *numa_info = numa_state->nodes;
|
|
|
|
|
|
|
|
for (i = 0; i < numa_state->num_nodes; i++) {
|
|
|
|
if (numa_info[i].initiator == MAX_NODES) {
|
|
|
|
error_report("The initiator of NUMA node %d is missing, use "
|
|
|
|
"'-numa node,initiator' option to declare it", i);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!numa_info[numa_info[i].initiator].present) {
|
|
|
|
error_report("NUMA node %" PRIu16 " is missing, use "
|
|
|
|
"'-numa node' option to declare it first",
|
|
|
|
numa_info[i].initiator);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!numa_info[numa_info[i].initiator].has_cpu) {
|
|
|
|
error_report("The initiator of NUMA node %d is invalid", i);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-04 10:37:39 +02:00
|
|
|
static void machine_numa_finish_cpu_init(MachineState *machine)
|
2017-05-10 13:29:59 +02:00
|
|
|
{
|
|
|
|
int i;
|
2017-05-30 18:23:57 +02:00
|
|
|
bool default_mapping;
|
2017-05-10 13:29:59 +02:00
|
|
|
GString *s = g_string_new(NULL);
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
|
|
|
const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(machine);
|
|
|
|
|
2019-08-09 08:57:22 +02:00
|
|
|
assert(machine->numa_state->num_nodes);
|
2017-05-30 18:23:57 +02:00
|
|
|
for (i = 0; i < possible_cpus->len; i++) {
|
|
|
|
if (possible_cpus->cpus[i].props.has_node_id) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default_mapping = (i == possible_cpus->len);
|
|
|
|
|
2017-05-10 13:29:59 +02:00
|
|
|
for (i = 0; i < possible_cpus->len; i++) {
|
|
|
|
const CPUArchId *cpu_slot = &possible_cpus->cpus[i];
|
|
|
|
|
|
|
|
if (!cpu_slot->props.has_node_id) {
|
2017-05-30 18:23:58 +02:00
|
|
|
/* fetch default mapping from board and enable it */
|
|
|
|
CpuInstanceProperties props = cpu_slot->props;
|
|
|
|
|
2017-06-01 12:53:28 +02:00
|
|
|
props.node_id = mc->get_default_cpu_node_id(machine, i);
|
2017-05-30 18:23:58 +02:00
|
|
|
if (!default_mapping) {
|
2017-05-30 18:23:57 +02:00
|
|
|
/* record slots with not set mapping,
|
|
|
|
* TODO: make it hard error in future */
|
|
|
|
char *cpu_str = cpu_slot_to_string(cpu_slot);
|
|
|
|
g_string_append_printf(s, "%sCPU %d [%s]",
|
|
|
|
s->len ? ", " : "", i, cpu_str);
|
|
|
|
g_free(cpu_str);
|
2017-05-30 18:23:58 +02:00
|
|
|
|
|
|
|
/* non mapped cpus used to fallback to node 0 */
|
|
|
|
props.node_id = 0;
|
2017-05-30 18:23:57 +02:00
|
|
|
}
|
2017-05-30 18:23:58 +02:00
|
|
|
|
|
|
|
props.has_node_id = true;
|
|
|
|
machine_set_cpu_numa_node(machine, &props, &error_fatal);
|
2017-05-10 13:29:59 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-13 02:19:22 +01:00
|
|
|
|
|
|
|
if (machine->numa_state->hmat_enabled) {
|
|
|
|
numa_validate_initiator(machine->numa_state);
|
|
|
|
}
|
|
|
|
|
2017-05-18 10:09:31 +02:00
|
|
|
if (s->len && !qtest_enabled()) {
|
2017-07-12 15:57:41 +02:00
|
|
|
warn_report("CPU(s) not present in any NUMA nodes: %s",
|
|
|
|
s->str);
|
|
|
|
warn_report("All CPU(s) up to maxcpus should be described "
|
|
|
|
"in NUMA config, ability to start up with partial NUMA "
|
|
|
|
"mappings is obsoleted and will be removed in future");
|
2017-05-10 13:29:59 +02:00
|
|
|
}
|
|
|
|
g_string_free(s, true);
|
|
|
|
}
|
|
|
|
|
2017-05-10 13:29:58 +02:00
|
|
|
void machine_run_board_init(MachineState *machine)
|
|
|
|
{
|
|
|
|
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
|
2017-05-10 13:29:59 +02:00
|
|
|
|
2019-12-12 13:48:56 +01:00
|
|
|
if (machine->numa_state) {
|
2019-08-09 08:57:22 +02:00
|
|
|
numa_complete_configuration(machine);
|
|
|
|
if (machine->numa_state->num_nodes) {
|
|
|
|
machine_numa_finish_cpu_init(machine);
|
|
|
|
}
|
2018-07-10 12:51:29 +02:00
|
|
|
}
|
2017-10-03 22:05:09 +02:00
|
|
|
|
|
|
|
/* If the machine supports the valid_cpu_types check and the user
|
|
|
|
* specified a CPU with -cpu check here that the user CPU is supported.
|
|
|
|
*/
|
|
|
|
if (machine_class->valid_cpu_types && machine->cpu_type) {
|
|
|
|
ObjectClass *class = object_class_by_name(machine->cpu_type);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; machine_class->valid_cpu_types[i]; i++) {
|
|
|
|
if (object_class_dynamic_cast(class,
|
|
|
|
machine_class->valid_cpu_types[i])) {
|
|
|
|
/* The user specificed CPU is in the valid field, we are
|
|
|
|
* good to go.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!machine_class->valid_cpu_types[i]) {
|
|
|
|
/* The user specified CPU is not valid */
|
|
|
|
error_report("Invalid CPU type: %s", machine->cpu_type);
|
|
|
|
error_printf("The valid types are: %s",
|
|
|
|
machine_class->valid_cpu_types[0]);
|
|
|
|
for (i = 1; machine_class->valid_cpu_types[i]; i++) {
|
|
|
|
error_printf(", %s", machine_class->valid_cpu_types[i]);
|
|
|
|
}
|
|
|
|
error_printf("\n");
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-10 13:29:58 +02:00
|
|
|
machine_class->init(machine);
|
|
|
|
}
|
|
|
|
|
2014-03-05 18:30:45 +01:00
|
|
|
static const TypeInfo machine_info = {
|
|
|
|
.name = TYPE_MACHINE,
|
|
|
|
.parent = TYPE_OBJECT,
|
|
|
|
.abstract = true,
|
|
|
|
.class_size = sizeof(MachineClass),
|
2015-05-07 07:33:57 +02:00
|
|
|
.class_init = machine_class_init,
|
2015-08-20 23:54:35 +02:00
|
|
|
.class_base_init = machine_class_base_init,
|
2014-03-05 18:30:45 +01:00
|
|
|
.instance_size = sizeof(MachineState),
|
2014-05-26 14:40:58 +02:00
|
|
|
.instance_init = machine_initfn,
|
|
|
|
.instance_finalize = machine_finalize,
|
2014-03-05 18:30:45 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static void machine_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&machine_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(machine_register_types)
|