mirror of https://gitee.com/openkylin/qemu.git
* More Meson test conversions and configure cleanups
* Generalize XSAVE area offset so that it matches AMD processors on KVM * Improvements for -display and deprecation of -no-quit * Enable SMP configuration as a compound machine property ("-M smp.cpus=...") * Haiku compilation fix * Add icon on Darwin -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmDkB7sUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroOISgf+Nn5BiXQRY52DK/2PoG330F6UeOcp kWFAE4k4qEktDiCcd5xKekiUd7h+TiRS8bLeycmRtiSXvbzXioE2eCelui0SZDQl zpIb8wV2WaxrD/zUYPV7r5n+VFAaTCm9lUEzzqnwaThBG/Oat45gnossZEIWv85g KtQMsSh3pc+KpTjWbIA8V01ohzwFE2q7cA9CB/pDgR3h8M5p4K0ZdaPoAO2auhvu 2sbu9oBl1JwqpIhPme9JR6Je5fMCILBRlXTvPgJ/0iaGdxcNmZxoflO/TZVFB1pl tUiCu0GB0yEasMO1E6+cP7ezhm15Lz3vKqjr/boV5Y9osfU36k9xkLTvAg== =itIm -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging * More Meson test conversions and configure cleanups * Generalize XSAVE area offset so that it matches AMD processors on KVM * Improvements for -display and deprecation of -no-quit * Enable SMP configuration as a compound machine property ("-M smp.cpus=...") * Haiku compilation fix * Add icon on Darwin # gpg: Signature made Tue 06 Jul 2021 08:35:23 BST # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini-gitlab/tags/for-upstream: (40 commits) config-host.mak: remove unused compiler-related lines Set icon for QEMU binary on Mac OS qemu-option: remove now-dead code machine: add smp compound property vl: switch -M parsing to keyval keyval: introduce keyval_parse_into keyval: introduce keyval_merge qom: export more functions for use with non-UserCreatable objects configure: convert compiler tests to meson, part 6 configure: convert compiler tests to meson, part 5 configure: convert compiler tests to meson, part 4 configure: convert compiler tests to meson, part 3 configure: convert compiler tests to meson, part 2 configure: convert compiler tests to meson, part 1 configure: convert HAVE_BROKEN_SIZE_MAX to meson configure, meson: move CONFIG_IVSHMEM to meson meson: store dependency('threads') in a variable meson: sort existing compiler tests configure, meson: convert libxml2 detection to meson configure, meson: convert liburing detection to meson ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9aef095419
2
Makefile
2
Makefile
|
@ -14,7 +14,7 @@ SRC_PATH=.
|
|||
# we have explicit rules for everything
|
||||
MAKEFLAGS += -rR
|
||||
|
||||
SHELL = /usr/bin/env bash -o pipefail
|
||||
SHELL = bash -o pipefail
|
||||
|
||||
# Usage: $(call quiet-command,command and args,"NAME","args to print")
|
||||
# This will run "command and args", and either:
|
||||
|
|
|
@ -303,5 +303,5 @@ variable::
|
|||
host_kconfig = \
|
||||
('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \
|
||||
('CONFIG_SPICE' in config_host ? ['CONFIG_SPICE=y'] : []) + \
|
||||
('CONFIG_IVSHMEM' in config_host ? ['CONFIG_IVSHMEM=y'] : []) + \
|
||||
(have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \
|
||||
...
|
||||
|
|
|
@ -126,6 +126,18 @@ other options have been processed. This will either have no effect (if
|
|||
if they were not given. The property is therefore useless and should not be
|
||||
specified.
|
||||
|
||||
``-display sdl,window_close=...`` (since 6.1)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Use ``-display sdl,window-close=...`` instead (i.e. with a minus instead of
|
||||
an underscore between "window" and "close").
|
||||
|
||||
``-no-quit`` (since 6.1)
|
||||
''''''''''''''''''''''''
|
||||
|
||||
The ``-no-quit`` is a synonym for ``-display ...,window-close=off`` which
|
||||
should be used instead.
|
||||
|
||||
|
||||
QEMU Machine Protocol (QMP) commands
|
||||
------------------------------------
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "hw/loader.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-visit-common.h"
|
||||
#include "qapi/qapi-visit-machine.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/cpus.h"
|
||||
|
@ -799,6 +800,57 @@ static void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
|
|||
ms->smp.sockets = sockets;
|
||||
}
|
||||
|
||||
static void machine_get_smp(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(obj);
|
||||
SMPConfiguration *config = &(SMPConfiguration){
|
||||
.has_cores = true, .cores = ms->smp.cores,
|
||||
.has_sockets = true, .sockets = ms->smp.sockets,
|
||||
.has_dies = true, .dies = ms->smp.dies,
|
||||
.has_threads = true, .threads = ms->smp.threads,
|
||||
.has_cpus = true, .cpus = ms->smp.cpus,
|
||||
.has_maxcpus = true, .maxcpus = ms->smp.max_cpus,
|
||||
};
|
||||
if (!visit_type_SMPConfiguration(v, name, &config, &error_abort)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void machine_set_smp(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
||||
MachineState *ms = MACHINE(obj);
|
||||
SMPConfiguration *config;
|
||||
ERRP_GUARD();
|
||||
|
||||
if (!visit_type_SMPConfiguration(v, name, &config, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mc->smp_parse(ms, config, errp);
|
||||
if (errp) {
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* sanity-check smp_cpus and max_cpus against mc */
|
||||
if (ms->smp.cpus < mc->min_cpus) {
|
||||
error_setg(errp, "Invalid SMP CPUs %d. The min CPUs "
|
||||
"supported by machine '%s' is %d",
|
||||
ms->smp.cpus,
|
||||
mc->name, mc->min_cpus);
|
||||
} else if (ms->smp.max_cpus > mc->max_cpus) {
|
||||
error_setg(errp, "Invalid SMP CPUs %d. The max CPUs "
|
||||
"supported by machine '%s' is %d",
|
||||
current_machine->smp.max_cpus,
|
||||
mc->name, mc->max_cpus);
|
||||
}
|
||||
|
||||
out_free:
|
||||
qapi_free_SMPConfiguration(config);
|
||||
}
|
||||
|
||||
static void machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
@ -838,6 +890,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
|||
object_class_property_set_description(oc, "dumpdtb",
|
||||
"Dump current dtb to a file and quit");
|
||||
|
||||
object_class_property_add(oc, "smp", "SMPConfiguration",
|
||||
machine_get_smp, machine_set_smp,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "smp",
|
||||
"CPU topology");
|
||||
|
||||
object_class_property_add(oc, "phandle-start", "int",
|
||||
machine_get_phandle_start, machine_set_phandle_start,
|
||||
NULL, NULL);
|
||||
|
@ -1126,56 +1184,6 @@ MemoryRegion *machine_consume_memdev(MachineState *machine,
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool machine_smp_parse(MachineState *ms, QemuOpts *opts, Error **errp)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
ERRP_GUARD();
|
||||
|
||||
if (opts) {
|
||||
SMPConfiguration config = {
|
||||
.has_cpus = !!qemu_opt_get(opts, "cpus"),
|
||||
.cpus = qemu_opt_get_number(opts, "cpus", 0),
|
||||
.has_sockets = !!qemu_opt_get(opts, "sockets"),
|
||||
.sockets = qemu_opt_get_number(opts, "sockets", 0),
|
||||
.has_dies = !!qemu_opt_get(opts, "dies"),
|
||||
.dies = qemu_opt_get_number(opts, "dies", 0),
|
||||
.has_cores = !!qemu_opt_get(opts, "cores"),
|
||||
.cores = qemu_opt_get_number(opts, "cores", 0),
|
||||
.has_threads = !!qemu_opt_get(opts, "threads"),
|
||||
.threads = qemu_opt_get_number(opts, "threads", 0),
|
||||
.has_maxcpus = !!qemu_opt_get(opts, "maxcpus"),
|
||||
.maxcpus = qemu_opt_get_number(opts, "maxcpus", 0),
|
||||
};
|
||||
|
||||
mc->smp_parse(ms, &config, errp);
|
||||
if (*errp) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* sanity-check smp_cpus and max_cpus against mc */
|
||||
if (ms->smp.cpus < mc->min_cpus) {
|
||||
error_setg(errp, "Invalid SMP CPUs %d. The min CPUs "
|
||||
"supported by machine '%s' is %d",
|
||||
ms->smp.cpus,
|
||||
mc->name, mc->min_cpus);
|
||||
return false;
|
||||
} else if (ms->smp.max_cpus > mc->max_cpus) {
|
||||
error_setg(errp, "Invalid SMP CPUs %d. The max CPUs "
|
||||
"supported by machine '%s' is %d",
|
||||
current_machine->smp.max_cpus,
|
||||
mc->name, mc->max_cpus);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ms->smp.cpus > 1) {
|
||||
Error *blocker = NULL;
|
||||
error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp");
|
||||
replay_add_blocker(blocker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void machine_run_board_init(MachineState *machine)
|
||||
{
|
||||
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
|
||||
|
|
|
@ -61,7 +61,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
|
|||
hw_display_modules += {'virtio-gpu': virtio_gpu_ss}
|
||||
|
||||
virtio_gpu_gl_ss = ss.source_set()
|
||||
virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL', opengl],
|
||||
virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', virgl, opengl],
|
||||
if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl])
|
||||
hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss}
|
||||
endif
|
||||
|
@ -75,7 +75,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
|
|||
hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss}
|
||||
|
||||
virtio_gpu_pci_gl_ss = ss.source_set()
|
||||
virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', 'CONFIG_VIRGL', opengl],
|
||||
virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', virgl, opengl],
|
||||
if_true: [files('virtio-gpu-pci-gl.c'), pixman])
|
||||
hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss}
|
||||
endif
|
||||
|
@ -89,7 +89,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
|
|||
hw_display_modules += {'virtio-vga': virtio_vga_ss}
|
||||
|
||||
virtio_vga_gl_ss = ss.source_set()
|
||||
virtio_vga_gl_ss.add(when: ['CONFIG_VIRTIO_VGA', 'CONFIG_VIRGL', opengl],
|
||||
virtio_vga_gl_ss.add(when: ['CONFIG_VIRTIO_VGA', virgl, opengl],
|
||||
if_true: [files('virtio-vga-gl.c'), pixman])
|
||||
hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss}
|
||||
endif
|
||||
|
|
|
@ -26,7 +26,6 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE)
|
|||
extern MachineState *current_machine;
|
||||
|
||||
void machine_run_board_init(MachineState *machine);
|
||||
bool machine_smp_parse(MachineState *ms, QemuOpts *opts, Error **errp);
|
||||
bool machine_usb(MachineState *machine);
|
||||
int machine_phandle_start(MachineState *machine);
|
||||
bool machine_dump_guest_core(MachineState *machine);
|
||||
|
|
|
@ -119,7 +119,6 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
|
|||
int fail_if_exists, Error **errp);
|
||||
void qemu_opts_reset(QemuOptsList *list);
|
||||
void qemu_opts_loc_restore(QemuOpts *opts);
|
||||
bool qemu_opts_set(QemuOptsList *list, const char *name, const char *value, Error **errp);
|
||||
const char *qemu_opts_id(QemuOpts *opts);
|
||||
void qemu_opts_set_id(QemuOpts *opts, char *id);
|
||||
void qemu_opts_del(QemuOpts *opts);
|
||||
|
@ -130,8 +129,6 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
|
|||
bool permit_abbrev);
|
||||
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
|
||||
bool permit_abbrev, Error **errp);
|
||||
void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
|
||||
int permit_abbrev);
|
||||
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
|
||||
Error **errp);
|
||||
QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
|
||||
|
@ -147,7 +144,10 @@ void qemu_opts_print_help(QemuOptsList *list, bool print_caption);
|
|||
void qemu_opts_free(QemuOptsList *list);
|
||||
QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list);
|
||||
|
||||
QDict *keyval_parse_into(QDict *qdict, const char *params, const char *implied_key,
|
||||
bool *p_help, Error **errp);
|
||||
QDict *keyval_parse(const char *params, const char *implied_key,
|
||||
bool *help, Error **errp);
|
||||
void keyval_merge(QDict *old, const QDict *new, Error **errp);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -861,6 +861,29 @@ static void do_qemu_init_ ## type_array(void) \
|
|||
} \
|
||||
type_init(do_qemu_init_ ## type_array)
|
||||
|
||||
/**
|
||||
* type_print_class_properties:
|
||||
* @type: a QOM class name
|
||||
*
|
||||
* Print the object's class properties to stdout or the monitor.
|
||||
* Return whether an object was found.
|
||||
*/
|
||||
bool type_print_class_properties(const char *type);
|
||||
|
||||
/**
|
||||
* object_set_properties_from_keyval:
|
||||
* @obj: a QOM object
|
||||
* @qdict: a dictionary with the properties to be set
|
||||
* @from_json: true if leaf values of @qdict are typed, false if they
|
||||
* are strings
|
||||
* @errp: pointer to error object
|
||||
*
|
||||
* For each key in the dictionary, parse the value string if needed,
|
||||
* then set the corresponding property in @obj.
|
||||
*/
|
||||
void object_set_properties_from_keyval(Object *obj, const QDict *qdict,
|
||||
bool from_json, Error **errp);
|
||||
|
||||
/**
|
||||
* object_class_dynamic_cast_assert:
|
||||
* @klass: The #ObjectClass to attempt to cast.
|
||||
|
|
231
meson.build
231
meson.build
|
@ -164,6 +164,7 @@ endif
|
|||
multiprocess_allowed = targetos == 'linux' and not get_option('multiprocess').disabled()
|
||||
|
||||
libm = cc.find_library('m', required: false)
|
||||
threads = dependency('threads')
|
||||
util = cc.find_library('util', required: false)
|
||||
winmm = []
|
||||
socket = []
|
||||
|
@ -327,15 +328,16 @@ if have_system or have_tools
|
|||
endif
|
||||
libaio = cc.find_library('aio', required: false)
|
||||
zlib = dependency('zlib', required: true, kwargs: static_kwargs)
|
||||
|
||||
linux_io_uring = not_found
|
||||
if 'CONFIG_LINUX_IO_URING' in config_host
|
||||
linux_io_uring = declare_dependency(compile_args: config_host['LINUX_IO_URING_CFLAGS'].split(),
|
||||
link_args: config_host['LINUX_IO_URING_LIBS'].split())
|
||||
if not get_option('linux_io_uring').auto() or have_block
|
||||
linux_io_uring = dependency('liburing', required: get_option('linux_io_uring'),
|
||||
method: 'pkg-config', kwargs: static_kwargs)
|
||||
endif
|
||||
libxml2 = not_found
|
||||
if 'CONFIG_LIBXML2' in config_host
|
||||
libxml2 = declare_dependency(compile_args: config_host['LIBXML2_CFLAGS'].split(),
|
||||
link_args: config_host['LIBXML2_LIBS'].split())
|
||||
if not get_option('libxml2').auto() or have_block
|
||||
libxml2 = dependency('libxml-2.0', required: get_option('libxml2'),
|
||||
method: 'pkg-config', kwargs: static_kwargs)
|
||||
endif
|
||||
libnfs = not_found
|
||||
if not get_option('libnfs').auto() or have_block
|
||||
|
@ -471,9 +473,11 @@ if 'CONFIG_GBM' in config_host
|
|||
link_args: config_host['GBM_LIBS'].split())
|
||||
endif
|
||||
virgl = not_found
|
||||
if 'CONFIG_VIRGL' in config_host
|
||||
virgl = declare_dependency(compile_args: config_host['VIRGL_CFLAGS'].split(),
|
||||
link_args: config_host['VIRGL_LIBS'].split())
|
||||
if not get_option('virglrenderer').auto() or have_system
|
||||
virgl = dependency('virglrenderer',
|
||||
method: 'pkg-config',
|
||||
required: get_option('virglrenderer'),
|
||||
kwargs: static_kwargs)
|
||||
endif
|
||||
curl = not_found
|
||||
if not get_option('curl').auto() or have_block
|
||||
|
@ -860,6 +864,7 @@ endif
|
|||
|
||||
gtk = not_found
|
||||
gtkx11 = not_found
|
||||
vte = not_found
|
||||
if not get_option('gtk').auto() or (have_system and not cocoa.found())
|
||||
gtk = dependency('gtk+-3.0', version: '>=3.22.0',
|
||||
method: 'pkg-config',
|
||||
|
@ -871,14 +876,16 @@ if not get_option('gtk').auto() or (have_system and not cocoa.found())
|
|||
required: false,
|
||||
kwargs: static_kwargs)
|
||||
gtk = declare_dependency(dependencies: [gtk, gtkx11])
|
||||
|
||||
if not get_option('vte').auto() or have_system
|
||||
vte = dependency('vte-2.91',
|
||||
method: 'pkg-config',
|
||||
required: get_option('vte'),
|
||||
kwargs: static_kwargs)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
vte = not_found
|
||||
if 'CONFIG_VTE' in config_host
|
||||
vte = declare_dependency(compile_args: config_host['VTE_CFLAGS'].split(),
|
||||
link_args: config_host['VTE_LIBS'].split())
|
||||
endif
|
||||
x11 = not_found
|
||||
if gtkx11.found()
|
||||
x11 = dependency('x11', method: 'pkg-config', required: gtkx11.found(),
|
||||
|
@ -1001,13 +1008,15 @@ if not get_option('libusb').auto() or have_system
|
|||
endif
|
||||
|
||||
libpmem = not_found
|
||||
if 'CONFIG_LIBPMEM' in config_host
|
||||
libpmem = declare_dependency(compile_args: config_host['LIBPMEM_CFLAGS'].split(),
|
||||
link_args: config_host['LIBPMEM_LIBS'].split())
|
||||
if not get_option('libpmem').auto() or have_system
|
||||
libpmem = dependency('libpmem', required: get_option('libpmem'),
|
||||
method: 'pkg-config', kwargs: static_kwargs)
|
||||
endif
|
||||
libdaxctl = not_found
|
||||
if 'CONFIG_LIBDAXCTL' in config_host
|
||||
libdaxctl = declare_dependency(link_args: config_host['LIBDAXCTL_LIBS'].split())
|
||||
if not get_option('libdaxctl').auto() or have_system
|
||||
libdaxctl = dependency('libdaxctl', required: get_option('libdaxctl'),
|
||||
version: '>=57', method: 'pkg-config',
|
||||
kwargs: static_kwargs)
|
||||
endif
|
||||
tasn1 = not_found
|
||||
if gnutls.found()
|
||||
|
@ -1042,10 +1051,12 @@ endif
|
|||
|
||||
# Check whether the glibc provides statx()
|
||||
|
||||
statx_test = '''
|
||||
gnu_source_prefix = '''
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
'''
|
||||
statx_test = gnu_source_prefix + '''
|
||||
#include <sys/stat.h>
|
||||
int main(void) {
|
||||
struct statx statxbuf;
|
||||
|
@ -1208,6 +1219,7 @@ if glusterfs.found()
|
|||
config_host_data.set('CONFIG_GLUSTERFS_IOCB_HAS_STAT', glusterfs_iocb_has_stat)
|
||||
endif
|
||||
config_host_data.set('CONFIG_GTK', gtk.found())
|
||||
config_host_data.set('CONFIG_VTE', vte.found())
|
||||
config_host_data.set('CONFIG_LIBATTR', have_old_libattr)
|
||||
config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
|
||||
config_host_data.set('CONFIG_EBPF', libbpf.found())
|
||||
|
@ -1244,16 +1256,150 @@ config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0]
|
|||
config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
|
||||
config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2])
|
||||
|
||||
config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device)
|
||||
|
||||
# has_header
|
||||
config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h'))
|
||||
config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h'))
|
||||
config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h'))
|
||||
config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h'))
|
||||
config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h'))
|
||||
config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h'))
|
||||
config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h'))
|
||||
config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h'))
|
||||
config_host_data.set('HAVE_SYS_KCOV_H', cc.has_header('sys/kcov.h'))
|
||||
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
|
||||
config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device)
|
||||
config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h'))
|
||||
|
||||
# has_function
|
||||
config_host_data.set('CONFIG_ACCEPT4', cc.has_function('accept4'))
|
||||
config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime'))
|
||||
config_host_data.set('CONFIG_DUP3', cc.has_function('dup3'))
|
||||
config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate'))
|
||||
config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
|
||||
config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign'))
|
||||
config_host_data.set('CONFIG_PPOLL', cc.has_function('ppoll'))
|
||||
config_host_data.set('CONFIG_PREADV', cc.has_function('preadv', prefix: '#include <sys/uio.h>'))
|
||||
config_host_data.set('CONFIG_SEM_TIMEDWAIT', cc.has_function('sem_timedwait', dependencies: threads))
|
||||
config_host_data.set('CONFIG_SENDFILE', cc.has_function('sendfile'))
|
||||
config_host_data.set('CONFIG_SETNS', cc.has_function('setns') and cc.has_function('unshare'))
|
||||
config_host_data.set('CONFIG_SYNCFS', cc.has_function('syncfs'))
|
||||
config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range'))
|
||||
config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
|
||||
config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
|
||||
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
|
||||
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
|
||||
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
|
||||
|
||||
# has_header_symbol
|
||||
config_host_data.set('CONFIG_BYTESWAP_H',
|
||||
cc.has_header_symbol('byteswap.h', 'bswap_32'))
|
||||
config_host_data.set('CONFIG_EPOLL_CREATE1',
|
||||
cc.has_header_symbol('sys/epoll.h', 'epoll_create1'))
|
||||
config_host_data.set('CONFIG_HAS_ENVIRON',
|
||||
cc.has_header_symbol('unistd.h', 'environ', prefix: gnu_source_prefix))
|
||||
config_host_data.set('CONFIG_FALLOCATE_PUNCH_HOLE',
|
||||
cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_PUNCH_HOLE') and
|
||||
cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_KEEP_SIZE'))
|
||||
config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE',
|
||||
cc.has_header_symbol('linux/falloc.h', 'FALLOC_FL_ZERO_RANGE'))
|
||||
config_host_data.set('CONFIG_FIEMAP',
|
||||
cc.has_header('linux/fiemap.h') and
|
||||
cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP'))
|
||||
config_host_data.set('CONFIG_GETRANDOM',
|
||||
cc.has_function('getrandom') and
|
||||
cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK'))
|
||||
config_host_data.set('CONFIG_INOTIFY',
|
||||
cc.has_header_symbol('sys/inotify.h', 'inotify_init'))
|
||||
config_host_data.set('CONFIG_INOTIFY1',
|
||||
cc.has_header_symbol('sys/inotify.h', 'inotify_init1'))
|
||||
config_host_data.set('CONFIG_MACHINE_BSWAP_H',
|
||||
cc.has_header_symbol('machine/bswap.h', 'bswap32',
|
||||
prefix: '''#include <sys/endian.h>
|
||||
#include <sys/types.h>'''))
|
||||
config_host_data.set('CONFIG_PRCTL_PR_SET_TIMERSLACK',
|
||||
cc.has_header_symbol('sys/prctl.h', 'PR_SET_TIMERSLACK'))
|
||||
config_host_data.set('CONFIG_RTNETLINK',
|
||||
cc.has_header_symbol('linux/rtnetlink.h', 'IFLA_PROTO_DOWN'))
|
||||
config_host_data.set('CONFIG_SYSMACROS',
|
||||
cc.has_header_symbol('sys/sysmacros.h', 'makedev'))
|
||||
config_host_data.set('HAVE_OPTRESET',
|
||||
cc.has_header_symbol('getopt.h', 'optreset'))
|
||||
config_host_data.set('HAVE_UTMPX',
|
||||
cc.has_header_symbol('utmpx.h', 'struct utmpx'))
|
||||
|
||||
# has_member
|
||||
config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',
|
||||
cc.has_member('struct sigevent', 'sigev_notify_thread_id',
|
||||
prefix: '#include <signal.h>'))
|
||||
config_host_data.set('HAVE_STRUCT_STAT_ST_ATIM',
|
||||
cc.has_member('struct stat', 'st_atim',
|
||||
prefix: '#include <sys/stat.h>'))
|
||||
|
||||
config_host_data.set('CONFIG_EVENTFD', cc.compiles('''
|
||||
#include <sys/eventfd.h>
|
||||
int main(void) { return eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); }'''))
|
||||
config_host_data.set('CONFIG_FDATASYNC', cc.compiles(gnu_source_prefix + '''
|
||||
#include <unistd.h>
|
||||
int main(void) {
|
||||
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
|
||||
return fdatasync(0);
|
||||
#else
|
||||
#error Not supported
|
||||
#endif
|
||||
}'''))
|
||||
config_host_data.set('CONFIG_MADVISE', cc.compiles(gnu_source_prefix + '''
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stddef.h>
|
||||
int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }'''))
|
||||
config_host_data.set('CONFIG_MEMFD', cc.compiles(gnu_source_prefix + '''
|
||||
#include <sys/mman.h>
|
||||
int main(void) { return memfd_create("foo", MFD_ALLOW_SEALING); }'''))
|
||||
config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.compiles(gnu_source_prefix + '''
|
||||
#include <fcntl.h>
|
||||
#if !defined(AT_EMPTY_PATH)
|
||||
# error missing definition
|
||||
#else
|
||||
int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); }
|
||||
#endif'''))
|
||||
config_host_data.set('CONFIG_PIPE2', cc.compiles(gnu_source_prefix + '''
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int pipefd[2];
|
||||
return pipe2(pipefd, O_CLOEXEC);
|
||||
}'''))
|
||||
config_host_data.set('CONFIG_POSIX_MADVISE', cc.compiles(gnu_source_prefix + '''
|
||||
#include <sys/mman.h>
|
||||
#include <stddef.h>
|
||||
int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }'''))
|
||||
config_host_data.set('CONFIG_SIGNALFD', cc.compiles(gnu_source_prefix + '''
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <signal.h>
|
||||
int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }'''))
|
||||
config_host_data.set('CONFIG_SPLICE', cc.compiles(gnu_source_prefix + '''
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int len, fd = 0;
|
||||
len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
|
||||
splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
|
||||
return 0;
|
||||
}'''))
|
||||
|
||||
# Some versions of Mac OS X incorrectly define SIZE_MAX
|
||||
config_host_data.set('HAVE_BROKEN_SIZE_MAX', not cc.compiles('''
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
int main(int argc, char *argv[]) {
|
||||
return printf("%zu", SIZE_MAX);
|
||||
}''', args: ['-Werror']))
|
||||
|
||||
|
||||
ignored = ['CONFIG_QEMU_INTERP_PREFIX'] # actually per-target
|
||||
arrays = ['CONFIG_AUDIO_DRIVERS', 'CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST']
|
||||
|
@ -1322,10 +1468,11 @@ if link_language == 'cpp'
|
|||
}
|
||||
endif
|
||||
|
||||
have_ivshmem = config_host_data.get('CONFIG_EVENTFD')
|
||||
host_kconfig = \
|
||||
('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \
|
||||
('CONFIG_SPICE' in config_host ? ['CONFIG_SPICE=y'] : []) + \
|
||||
('CONFIG_IVSHMEM' in config_host ? ['CONFIG_IVSHMEM=y'] : []) + \
|
||||
(have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \
|
||||
('CONFIG_OPENGL' in config_host ? ['CONFIG_OPENGL=y'] : []) + \
|
||||
(x11.found() ? ['CONFIG_X11=y'] : []) + \
|
||||
('CONFIG_VHOST_USER' in config_host ? ['CONFIG_VHOST_USER=y'] : []) + \
|
||||
|
@ -1987,7 +2134,7 @@ util_ss.add_all(trace_ss)
|
|||
util_ss = util_ss.apply(config_all, strict: false)
|
||||
libqemuutil = static_library('qemuutil',
|
||||
sources: util_ss.sources() + stub_ss.sources() + genh,
|
||||
dependencies: [util_ss.dependencies(), libm, glib, socket, malloc, pixman])
|
||||
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
|
||||
qemuutil = declare_dependency(link_with: libqemuutil,
|
||||
sources: genh + version_res)
|
||||
|
||||
|
@ -2360,8 +2507,7 @@ foreach target : target_dirs
|
|||
endif
|
||||
foreach exe: execs
|
||||
exe_name = exe['name']
|
||||
exe_sign = 'CONFIG_HVF' in config_target
|
||||
if exe_sign
|
||||
if targetos == 'darwin'
|
||||
exe_name += '-unsigned'
|
||||
endif
|
||||
|
||||
|
@ -2375,7 +2521,13 @@ foreach target : target_dirs
|
|||
link_args: link_args,
|
||||
gui_app: exe['gui'])
|
||||
|
||||
if exe_sign
|
||||
if 'CONFIG_HVF' in config_target
|
||||
entitlements = meson.current_source_dir() / 'accel/hvf/entitlements.plist'
|
||||
else
|
||||
entitlements = '/dev/null'
|
||||
endif
|
||||
if targetos == 'darwin'
|
||||
icon = meson.current_source_dir() / 'pc-bios/qemu.rsrc'
|
||||
emulators += {exe['name'] : custom_target(exe['name'],
|
||||
depends: emulator,
|
||||
output: exe['name'],
|
||||
|
@ -2383,14 +2535,14 @@ foreach target : target_dirs
|
|||
meson.current_source_dir() / 'scripts/entitlement.sh',
|
||||
meson.current_build_dir() / exe_name,
|
||||
meson.current_build_dir() / exe['name'],
|
||||
meson.current_source_dir() / 'accel/hvf/entitlements.plist'
|
||||
entitlements, icon
|
||||
])
|
||||
}
|
||||
|
||||
meson.add_install_script('scripts/entitlement.sh', '--install',
|
||||
get_option('bindir') / exe_name,
|
||||
get_option('bindir') / exe['name'],
|
||||
meson.current_source_dir() / 'accel/hvf/entitlements.plist')
|
||||
entitlements, icon)
|
||||
else
|
||||
emulators += {exe['name']: emulator}
|
||||
endif
|
||||
|
@ -2476,7 +2628,7 @@ if have_tools
|
|||
install: true)
|
||||
endif
|
||||
|
||||
if 'CONFIG_IVSHMEM' in config_host
|
||||
if have_ivshmem
|
||||
subdir('contrib/ivshmem-client')
|
||||
subdir('contrib/ivshmem-server')
|
||||
endif
|
||||
|
@ -2613,7 +2765,6 @@ if targetos == 'windows'
|
|||
summary_info += {'Windows SDK': config_host['WIN_SDK']}
|
||||
endif
|
||||
endif
|
||||
summary_info += {'ARFLAGS': config_host['ARFLAGS']}
|
||||
summary_info += {'CFLAGS': ' '.join(get_option('c_args')
|
||||
+ ['-O' + get_option('optimization')]
|
||||
+ (get_option('debug') ? ['-g'] : []))}
|
||||
|
@ -2634,10 +2785,6 @@ summary_info += {'PIE': get_option('b_pie')}
|
|||
summary_info += {'static build': config_host.has_key('CONFIG_STATIC')}
|
||||
summary_info += {'malloc trim support': has_malloc_trim}
|
||||
summary_info += {'membarrier': config_host.has_key('CONFIG_MEMBARRIER')}
|
||||
summary_info += {'fdatasync': config_host.has_key('CONFIG_FDATASYNC')}
|
||||
summary_info += {'madvise': config_host.has_key('CONFIG_MADVISE')}
|
||||
summary_info += {'posix_madvise': config_host.has_key('CONFIG_POSIX_MADVISE')}
|
||||
summary_info += {'posix_memalign': config_host.has_key('CONFIG_POSIX_MEMALIGN')}
|
||||
summary_info += {'debug stack usage': config_host.has_key('CONFIG_DEBUG_STACK_USAGE')}
|
||||
summary_info += {'mutex debugging': config_host.has_key('CONFIG_DEBUG_MUTEX')}
|
||||
summary_info += {'memory allocator': get_option('malloc')}
|
||||
|
@ -2756,7 +2903,7 @@ summary_info += {'SDL image support': sdl_image.found()}
|
|||
summary_info += {'GTK support': gtk.found()}
|
||||
summary_info += {'pixman': pixman.found()}
|
||||
# TODO: add back version
|
||||
summary_info += {'VTE support': config_host.has_key('CONFIG_VTE')}
|
||||
summary_info += {'VTE support': vte.found()}
|
||||
# TODO: add back version
|
||||
summary_info += {'slirp support': slirp_opt == 'disabled' ? false : slirp_opt}
|
||||
summary_info += {'libtasn1': tasn1.found()}
|
||||
|
@ -2764,7 +2911,7 @@ summary_info += {'PAM': pam.found()}
|
|||
summary_info += {'iconv support': iconv.found()}
|
||||
summary_info += {'curses support': curses.found()}
|
||||
# TODO: add back version
|
||||
summary_info += {'virgl support': config_host.has_key('CONFIG_VIRGL')}
|
||||
summary_info += {'virgl support': virgl.found()}
|
||||
summary_info += {'curl support': curl.found()}
|
||||
summary_info += {'Multipath support': mpathpersist.found()}
|
||||
summary_info += {'VNC support': vnc.found()}
|
||||
|
@ -2777,7 +2924,7 @@ summary_info += {'brlapi support': brlapi.found()}
|
|||
summary_info += {'vde support': config_host.has_key('CONFIG_VDE')}
|
||||
summary_info += {'netmap support': config_host.has_key('CONFIG_NETMAP')}
|
||||
summary_info += {'Linux AIO support': config_host.has_key('CONFIG_LINUX_AIO')}
|
||||
summary_info += {'Linux io_uring support': config_host.has_key('CONFIG_LINUX_IO_URING')}
|
||||
summary_info += {'Linux io_uring support': linux_io_uring.found()}
|
||||
summary_info += {'ATTR/XATTR support': libattr.found()}
|
||||
summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')}
|
||||
summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')}
|
||||
|
@ -2812,10 +2959,10 @@ summary_info += {'bzip2 support': libbzip2.found()}
|
|||
summary_info += {'lzfse support': liblzfse.found()}
|
||||
summary_info += {'zstd support': zstd.found()}
|
||||
summary_info += {'NUMA host support': config_host.has_key('CONFIG_NUMA')}
|
||||
summary_info += {'libxml2': config_host.has_key('CONFIG_LIBXML2')}
|
||||
summary_info += {'libxml2': libxml2.found()}
|
||||
summary_info += {'capstone': capstone_opt == 'disabled' ? false : capstone_opt}
|
||||
summary_info += {'libpmem support': config_host.has_key('CONFIG_LIBPMEM')}
|
||||
summary_info += {'libdaxctl support': config_host.has_key('CONFIG_LIBDAXCTL')}
|
||||
summary_info += {'libpmem support': libpmem.found()}
|
||||
summary_info += {'libdaxctl support': libdaxctl.found()}
|
||||
summary_info += {'libudev': libudev.found()}
|
||||
summary_info += {'FUSE lseek': fuse_lseek.found()}
|
||||
summary(summary_info, bool_yn: true, section: 'Dependencies')
|
||||
|
|
|
@ -84,10 +84,18 @@ option('nettle', type : 'feature', value : 'auto',
|
|||
description: 'nettle cryptography support')
|
||||
option('gcrypt', type : 'feature', value : 'auto',
|
||||
description: 'libgcrypt cryptography support')
|
||||
option('libdaxctl', type : 'feature', value : 'auto',
|
||||
description: 'libdaxctl support')
|
||||
option('libpmem', type : 'feature', value : 'auto',
|
||||
description: 'libpmem support')
|
||||
option('libudev', type : 'feature', value : 'auto',
|
||||
description: 'Use libudev to enumerate host devices')
|
||||
option('libusb', type : 'feature', value : 'auto',
|
||||
description: 'libusb support for USB passthrough')
|
||||
option('libxml2', type : 'feature', value : 'auto',
|
||||
description: 'libxml2 support for Parallels image format')
|
||||
option('linux_io_uring', type : 'feature', value : 'auto',
|
||||
description: 'Linux io_uring support')
|
||||
option('lzfse', type : 'feature', value : 'auto',
|
||||
description: 'lzfse support for DMG images')
|
||||
option('lzo', type : 'feature', value : 'auto',
|
||||
|
@ -110,6 +118,8 @@ option('u2f', type : 'feature', value : 'auto',
|
|||
description: 'U2F emulation support')
|
||||
option('usb_redir', type : 'feature', value : 'auto',
|
||||
description: 'libusbredir support')
|
||||
option('virglrenderer', type : 'feature', value : 'auto',
|
||||
description: 'virgl rendering support')
|
||||
option('vnc', type : 'feature', value : 'enabled',
|
||||
description: 'VNC server')
|
||||
option('vnc_jpeg', type : 'feature', value : 'auto',
|
||||
|
@ -118,6 +128,8 @@ option('vnc_png', type : 'feature', value : 'auto',
|
|||
description: 'PNG compression for VNC server')
|
||||
option('vnc_sasl', type : 'feature', value : 'auto',
|
||||
description: 'SASL authentication for VNC server')
|
||||
option('vte', type : 'feature', value : 'auto',
|
||||
description: 'vte support for the gtk UI')
|
||||
option('xkbcommon', type : 'feature', value : 'auto',
|
||||
description: 'xkbcommon support')
|
||||
option('zstd', type : 'feature', value : 'auto',
|
||||
|
|
|
@ -1783,11 +1783,12 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
|
|||
"-display spice-app[,gl=on|off]\n"
|
||||
#endif
|
||||
#if defined(CONFIG_SDL)
|
||||
"-display sdl[,alt_grab=on|off][,ctrl_grab=on|off]\n"
|
||||
" [,window_close=on|off][,gl=on|core|es|off]\n"
|
||||
"-display sdl[,alt_grab=on|off][,ctrl_grab=on|off][,gl=on|core|es|off]\n"
|
||||
" [,show-cursor=on|off][,window-close=on|off]\n"
|
||||
#endif
|
||||
#if defined(CONFIG_GTK)
|
||||
"-display gtk[,grab_on_hover=on|off][,gl=on|off]|\n"
|
||||
"-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n"
|
||||
" [,show-cursor=on|off][,window-close=on|off]\n"
|
||||
#endif
|
||||
#if defined(CONFIG_VNC)
|
||||
"-display vnc=<display>[,<optargs>]\n"
|
||||
|
@ -1824,17 +1825,37 @@ SRST
|
|||
application. The Spice server will redirect the serial consoles
|
||||
and QEMU monitors. (Since 4.0)
|
||||
|
||||
``sdl[,window-close=on|off][,gl=on|core|es|off]``
|
||||
|
||||
``sdl``
|
||||
Display video output via SDL (usually in a separate graphics
|
||||
window; see the SDL documentation for other possibilities).
|
||||
Valid parameters are:
|
||||
|
||||
``gtk[,grab-on-hover=on|off][,gl=on|off]``
|
||||
``alt_grab=on|off`` : Use Control+Alt+Shift-g to toggle mouse grabbing
|
||||
|
||||
``ctrl_grab=on|off`` : Use Right-Control-g to toggle mouse grabbing
|
||||
|
||||
``gl=on|off|core|es`` : Use OpenGL for displaying
|
||||
|
||||
``show-cursor=on|off`` : Force showing the mouse cursor
|
||||
|
||||
``window-close=on|off`` : Allow to quit qemu with window close button
|
||||
|
||||
``gtk``
|
||||
Display video output in a GTK window. This interface provides
|
||||
drop-down menus and other UI elements to configure and control
|
||||
the VM during runtime.
|
||||
the VM during runtime. Valid parameters are:
|
||||
|
||||
``curses [,charset=<encoding>]``
|
||||
``full-screen=on|off`` : Start in fullscreen mode
|
||||
|
||||
``gl=on|off`` : Use OpenGL for displaying
|
||||
|
||||
``grab-on-hover=on|off`` : Grab keyboard input on mouse hover
|
||||
|
||||
``show-cursor=on|off`` : Force showing the mouse cursor
|
||||
|
||||
``window-close=on|off`` : Allow to quit qemu with window close button
|
||||
|
||||
``curses[,charset=<encoding>]``
|
||||
Display video output via curses. For graphics device models
|
||||
which support a text mode, QEMU can display this output using a
|
||||
curses/ncurses interface. Nothing is displayed when the graphics
|
||||
|
@ -1845,11 +1866,14 @@ SRST
|
|||
``charset=CP850`` for IBM CP850 encoding. The default is
|
||||
``CP437``.
|
||||
|
||||
``egl-headless[,rendernode<file>]``
|
||||
``egl-headless[,rendernode=<file>]``
|
||||
Offload all OpenGL operations to a local DRI device. For any
|
||||
graphical display, this display needs to be paired with either
|
||||
VNC or SPICE displays.
|
||||
|
||||
``vnc=<display>``
|
||||
Start a VNC server on display <display>
|
||||
|
||||
``none``
|
||||
Do not display video output. The guest will still see an
|
||||
emulated graphics card, but its output will not be displayed to
|
||||
|
@ -1857,9 +1881,6 @@ SRST
|
|||
that it only affects what is done with video output; -nographic
|
||||
also changes the destination of the serial and parallel port
|
||||
data.
|
||||
|
||||
|
||||
|
||||
ERST
|
||||
|
||||
DEF("nographic", 0, QEMU_OPTION_nographic,
|
||||
|
@ -1910,10 +1931,11 @@ SRST
|
|||
ERST
|
||||
|
||||
DEF("no-quit", 0, QEMU_OPTION_no_quit,
|
||||
"-no-quit disable SDL window close capability\n", QEMU_ARCH_ALL)
|
||||
"-no-quit disable SDL/GTK window close capability (deprecated)\n", QEMU_ARCH_ALL)
|
||||
SRST
|
||||
``-no-quit``
|
||||
Disable SDL window close capability.
|
||||
Disable window close capability (SDL and GTK only). This option is
|
||||
deprecated, please use ``-display ...,window-close=off`` instead.
|
||||
ERST
|
||||
|
||||
DEF("sdl", 0, QEMU_OPTION_sdl,
|
||||
|
|
|
@ -42,6 +42,44 @@ bool user_creatable_can_be_deleted(UserCreatable *uc)
|
|||
}
|
||||
}
|
||||
|
||||
static void object_set_properties_from_qdict(Object *obj, const QDict *qdict,
|
||||
Visitor *v, Error **errp)
|
||||
{
|
||||
const QDictEntry *e;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!visit_start_struct(v, NULL, NULL, 0, &local_err)) {
|
||||
goto out;
|
||||
}
|
||||
for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
|
||||
if (!object_property_set(obj, e->key, v, &local_err)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!local_err) {
|
||||
visit_check_struct(v, &local_err);
|
||||
}
|
||||
visit_end_struct(v, NULL);
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
}
|
||||
|
||||
void object_set_properties_from_keyval(Object *obj, const QDict *qdict,
|
||||
bool from_json, Error **errp)
|
||||
{
|
||||
Visitor *v;
|
||||
if (from_json) {
|
||||
v = qobject_input_visitor_new(QOBJECT(qdict));
|
||||
} else {
|
||||
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
|
||||
}
|
||||
object_set_properties_from_qdict(obj, qdict, v, errp);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
Object *user_creatable_add_type(const char *type, const char *id,
|
||||
const QDict *qdict,
|
||||
Visitor *v, Error **errp)
|
||||
|
@ -49,7 +87,6 @@ Object *user_creatable_add_type(const char *type, const char *id,
|
|||
ERRP_GUARD();
|
||||
Object *obj;
|
||||
ObjectClass *klass;
|
||||
const QDictEntry *e;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (id != NULL && !id_wellformed(id)) {
|
||||
|
@ -78,18 +115,7 @@ Object *user_creatable_add_type(const char *type, const char *id,
|
|||
|
||||
assert(qdict);
|
||||
obj = object_new(type);
|
||||
if (!visit_start_struct(v, NULL, NULL, 0, &local_err)) {
|
||||
goto out;
|
||||
}
|
||||
for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
|
||||
if (!object_property_set(obj, e->key, v, &local_err)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!local_err) {
|
||||
visit_check_struct(v, &local_err);
|
||||
}
|
||||
visit_end_struct(v, NULL);
|
||||
object_set_properties_from_qdict(obj, qdict, v, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -178,7 +204,7 @@ static void user_creatable_print_types(void)
|
|||
g_slist_free(list);
|
||||
}
|
||||
|
||||
static bool user_creatable_print_type_properites(const char *type)
|
||||
bool type_print_class_properties(const char *type)
|
||||
{
|
||||
ObjectClass *klass;
|
||||
ObjectPropertyIterator iter;
|
||||
|
@ -224,7 +250,7 @@ bool user_creatable_print_help(const char *type, QemuOpts *opts)
|
|||
}
|
||||
|
||||
if (qemu_opt_has_help_opt(opts)) {
|
||||
return user_creatable_print_type_properites(type);
|
||||
return type_print_class_properties(type);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -234,7 +260,7 @@ static void user_creatable_print_help_from_qdict(QDict *args)
|
|||
{
|
||||
const char *type = qdict_get_try_str(args, "qom-type");
|
||||
|
||||
if (!type || !user_creatable_print_type_properites(type)) {
|
||||
if (!type || !type_print_class_properties(type)) {
|
||||
user_creatable_print_types();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,6 @@ hppa
|
|||
i386
|
||||
~ (/qemu)?((/include)?/hw/i386/.*|/target/i386/.*|/hw/intc/[^/]*apic[^/]*\.c)
|
||||
|
||||
lm32
|
||||
~ (/qemu)?((/include)?/hw/lm32/.*|/target/lm32/.*|/hw/.*/(milkymist|lm32).*)
|
||||
|
||||
m68k
|
||||
~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*)
|
||||
|
||||
|
@ -60,9 +57,6 @@ tilegx
|
|||
tricore
|
||||
~ (/qemu)?((/include)?/hw/tricore/.*|/target/tricore/.*)
|
||||
|
||||
unicore32
|
||||
~ (/qemu)?((/include)?/hw/unicore32/.*|/target/unicore32/.*)
|
||||
|
||||
9pfs
|
||||
~ (/qemu)?(/hw/9pfs/.*|/fsdev/.*)
|
||||
|
||||
|
|
|
@ -380,15 +380,17 @@ export PATH="$TOOLBIN:$PATH"
|
|||
|
||||
cd "$SRCDIR"
|
||||
|
||||
echo "Doing make distclean..."
|
||||
make distclean
|
||||
echo "Nuking build directory..."
|
||||
rm -rf +build
|
||||
mkdir +build
|
||||
cd +build
|
||||
|
||||
echo "Configuring..."
|
||||
# We configure with a fixed set of enables here to ensure that we don't
|
||||
# accidentally reduce the scope of the analysis by doing the build on
|
||||
# the system that's missing a dependency that we need to build part of
|
||||
# the codebase.
|
||||
./configure --disable-modules --enable-sdl --enable-gtk \
|
||||
../configure --disable-modules --enable-sdl --enable-gtk \
|
||||
--enable-opengl --enable-vte --enable-gnutls \
|
||||
--enable-nettle --enable-curses --enable-curl \
|
||||
--audio-drv-list=oss,alsa,sdl,pa --enable-virtfs \
|
||||
|
|
|
@ -11,6 +11,7 @@ fi
|
|||
SRC="$1"
|
||||
DST="$2"
|
||||
ENTITLEMENT="$3"
|
||||
ICON="$4"
|
||||
|
||||
if $in_place; then
|
||||
trap 'rm "$DST.tmp"' exit
|
||||
|
@ -20,6 +21,13 @@ else
|
|||
cd "$MESON_INSTALL_DESTDIR_PREFIX"
|
||||
fi
|
||||
|
||||
codesign --entitlements "$ENTITLEMENT" --force -s - "$SRC"
|
||||
if test "$ENTITLEMENT" != '/dev/null'; then
|
||||
codesign --entitlements "$ENTITLEMENT" --force -s - "$SRC"
|
||||
fi
|
||||
|
||||
# Add the QEMU icon to the binary on Mac OS
|
||||
Rez -append "$ICON" -o "$SRC"
|
||||
SetFile -a C "$SRC"
|
||||
|
||||
mv -f "$SRC" "$DST"
|
||||
trap '' exit
|
||||
|
|
359
softmmu/vl.c
359
softmmu/vl.c
|
@ -145,6 +145,8 @@ static const char *cpu_option;
|
|||
static const char *mem_path;
|
||||
static const char *incoming;
|
||||
static const char *loadvm;
|
||||
static const char *accelerators;
|
||||
static QDict *machine_opts_dict;
|
||||
static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts);
|
||||
static ram_addr_t maxram_size;
|
||||
static uint64_t ram_slots;
|
||||
|
@ -235,21 +237,6 @@ static QemuOptsList qemu_option_rom_opts = {
|
|||
},
|
||||
};
|
||||
|
||||
static QemuOptsList qemu_machine_opts = {
|
||||
.name = "machine",
|
||||
.implied_opt_name = "type",
|
||||
.merge_lists = true,
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
|
||||
.desc = {
|
||||
/*
|
||||
* no elements => accept any
|
||||
* sanity checking will happen later
|
||||
* when setting machine properties
|
||||
*/
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static QemuOptsList qemu_accel_opts = {
|
||||
.name = "accel",
|
||||
.implied_opt_name = "accel",
|
||||
|
@ -498,16 +485,6 @@ static QemuOptsList qemu_action_opts = {
|
|||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Get machine options
|
||||
*
|
||||
* Returns: machine options (never null).
|
||||
*/
|
||||
static QemuOpts *qemu_get_machine_opts(void)
|
||||
{
|
||||
return qemu_find_opts_singleton("machine");
|
||||
}
|
||||
|
||||
const char *qemu_get_vm_name(void)
|
||||
{
|
||||
return qemu_name;
|
||||
|
@ -815,33 +792,6 @@ static MachineClass *find_default_machine(GSList *machines)
|
|||
return default_machineclass;
|
||||
}
|
||||
|
||||
static int machine_help_func(QemuOpts *opts, MachineState *machine)
|
||||
{
|
||||
ObjectProperty *prop;
|
||||
ObjectPropertyIterator iter;
|
||||
|
||||
if (!qemu_opt_has_help_opt(opts)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
object_property_iter_init(&iter, OBJECT(machine));
|
||||
while ((prop = object_property_iter_next(&iter))) {
|
||||
if (!prop->set) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("%s.%s=%s", MACHINE_GET_CLASS(machine)->name,
|
||||
prop->name, prop->type);
|
||||
if (prop->description) {
|
||||
printf(" (%s)\n", prop->description);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void version(void)
|
||||
{
|
||||
printf("QEMU emulator version " QEMU_FULL_VERSION "\n"
|
||||
|
@ -1062,8 +1012,6 @@ static void parse_display(const char *p)
|
|||
* sdl DisplayType needs hand-crafted parser instead of
|
||||
* parse_display_qapi() due to some options not in
|
||||
* DisplayOptions, specifically:
|
||||
* - frame
|
||||
* Already deprecated.
|
||||
* - ctrl_grab + alt_grab
|
||||
* Not clear yet what happens to them long-term. Should
|
||||
* replaced by something better or deprecated and dropped.
|
||||
|
@ -1091,7 +1039,12 @@ static void parse_display(const char *p)
|
|||
} else {
|
||||
goto invalid_sdl_args;
|
||||
}
|
||||
} else if (strstart(opts, ",window_close=", &nextopt)) {
|
||||
} else if (strstart(opts, ",window_close=", &nextopt) ||
|
||||
strstart(opts, ",window-close=", &nextopt)) {
|
||||
if (strstart(opts, ",window_close=", NULL)) {
|
||||
warn_report("window_close with an underscore is deprecated,"
|
||||
" please use window-close instead.");
|
||||
}
|
||||
opts = nextopt;
|
||||
dpy.has_window_close = true;
|
||||
if (strstart(opts, "on", &nextopt)) {
|
||||
|
@ -1551,33 +1504,50 @@ static gint machine_class_cmp(gconstpointer a, gconstpointer b)
|
|||
object_class_get_name(OBJECT_CLASS(mc1)));
|
||||
}
|
||||
|
||||
static MachineClass *machine_parse(const char *name, GSList *machines)
|
||||
static void machine_help_func(const QDict *qdict)
|
||||
{
|
||||
MachineClass *mc;
|
||||
GSList *el;
|
||||
GSList *machines, *el;
|
||||
const char *type = qdict_get_try_str(qdict, "type");
|
||||
|
||||
if (is_help_option(name)) {
|
||||
printf("Supported machines are:\n");
|
||||
machines = g_slist_sort(machines, machine_class_cmp);
|
||||
for (el = machines; el; el = el->next) {
|
||||
MachineClass *mc = el->data;
|
||||
if (mc->alias) {
|
||||
printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
|
||||
}
|
||||
printf("%-20s %s%s%s\n", mc->name, mc->desc,
|
||||
mc->is_default ? " (default)" : "",
|
||||
mc->deprecation_reason ? " (deprecated)" : "");
|
||||
machines = object_class_get_list(TYPE_MACHINE, false);
|
||||
if (type) {
|
||||
ObjectClass *machine_class = OBJECT_CLASS(find_machine(type, machines));
|
||||
if (machine_class) {
|
||||
type_print_class_properties(object_class_get_name(machine_class));
|
||||
return;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
mc = find_machine(name, machines);
|
||||
if (!mc) {
|
||||
error_report("unsupported machine type");
|
||||
error_printf("Use -machine help to list supported machines\n");
|
||||
exit(1);
|
||||
printf("Supported machines are:\n");
|
||||
machines = g_slist_sort(machines, machine_class_cmp);
|
||||
for (el = machines; el; el = el->next) {
|
||||
MachineClass *mc = el->data;
|
||||
if (mc->alias) {
|
||||
printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
|
||||
}
|
||||
printf("%-20s %s%s%s\n", mc->name, mc->desc,
|
||||
mc->is_default ? " (default)" : "",
|
||||
mc->deprecation_reason ? " (deprecated)" : "");
|
||||
}
|
||||
return mc;
|
||||
}
|
||||
|
||||
static void
|
||||
machine_parse_property_opt(QemuOptsList *opts_list, const char *propname,
|
||||
const char *arg, Error **errp)
|
||||
{
|
||||
QDict *opts, *prop;
|
||||
bool help = false;
|
||||
ERRP_GUARD();
|
||||
|
||||
prop = keyval_parse(arg, opts_list->implied_opt_name, &help, errp);
|
||||
if (help) {
|
||||
qemu_opts_print_help(opts_list, true);
|
||||
return;
|
||||
}
|
||||
opts = qdict_new();
|
||||
qdict_put(opts, propname, prop);
|
||||
keyval_merge(machine_opts_dict, opts, errp);
|
||||
qobject_unref(opts);
|
||||
}
|
||||
|
||||
static const char *pid_file;
|
||||
|
@ -1630,32 +1600,31 @@ static const QEMUOption *lookup_opt(int argc, char **argv,
|
|||
return popt;
|
||||
}
|
||||
|
||||
static MachineClass *select_machine(void)
|
||||
static MachineClass *select_machine(QDict *qdict, Error **errp)
|
||||
{
|
||||
const char *optarg = qdict_get_try_str(qdict, "type");
|
||||
GSList *machines = object_class_get_list(TYPE_MACHINE, false);
|
||||
MachineClass *machine_class = find_default_machine(machines);
|
||||
const char *optarg;
|
||||
QemuOpts *opts;
|
||||
Location loc;
|
||||
MachineClass *machine_class;
|
||||
Error *local_err = NULL;
|
||||
|
||||
loc_push_none(&loc);
|
||||
|
||||
opts = qemu_get_machine_opts();
|
||||
qemu_opts_loc_restore(opts);
|
||||
|
||||
optarg = qemu_opt_get(opts, "type");
|
||||
if (optarg) {
|
||||
machine_class = machine_parse(optarg, machines);
|
||||
machine_class = find_machine(optarg, machines);
|
||||
qdict_del(qdict, "type");
|
||||
if (!machine_class) {
|
||||
error_setg(&local_err, "unsupported machine type");
|
||||
}
|
||||
} else {
|
||||
machine_class = find_default_machine(machines);
|
||||
if (!machine_class) {
|
||||
error_setg(&local_err, "No machine specified, and there is no default");
|
||||
}
|
||||
}
|
||||
|
||||
if (!machine_class) {
|
||||
error_report("No machine specified, and there is no default");
|
||||
error_printf("Use -machine help to list supported machines\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
loc_pop(&loc);
|
||||
g_slist_free(machines);
|
||||
if (local_err) {
|
||||
error_append_hint(&local_err, "Use -machine help to list supported machines\n");
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
return machine_class;
|
||||
}
|
||||
|
||||
|
@ -1674,42 +1643,70 @@ static int object_parse_property_opt(Object *obj,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int machine_set_property(void *opaque,
|
||||
const char *name, const char *value,
|
||||
Error **errp)
|
||||
/* *Non*recursively replace underscores with dashes in QDict keys. */
|
||||
static void keyval_dashify(QDict *qdict, Error **errp)
|
||||
{
|
||||
g_autofree char *qom_name = g_strdup(name);
|
||||
const QDictEntry *ent, *next;
|
||||
char *p;
|
||||
|
||||
for (p = qom_name; *p; p++) {
|
||||
if (*p == '_') {
|
||||
*p = '-';
|
||||
for (ent = qdict_first(qdict); ent; ent = next) {
|
||||
g_autofree char *new_key = NULL;
|
||||
|
||||
next = qdict_next(qdict, ent);
|
||||
if (!strchr(ent->key, '_')) {
|
||||
continue;
|
||||
}
|
||||
new_key = g_strdup(ent->key);
|
||||
for (p = new_key; *p; p++) {
|
||||
if (*p == '_') {
|
||||
*p = '-';
|
||||
}
|
||||
}
|
||||
if (qdict_haskey(qdict, new_key)) {
|
||||
error_setg(errp, "Conflict between '%s' and '%s'", ent->key, new_key);
|
||||
return;
|
||||
}
|
||||
qobject_ref(ent->value);
|
||||
qdict_put_obj(qdict, new_key, ent->value);
|
||||
qdict_del(qdict, ent->key);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_apply_legacy_machine_options(QDict *qdict)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
keyval_dashify(qdict, &error_fatal);
|
||||
|
||||
/* Legacy options do not correspond to MachineState properties. */
|
||||
if (g_str_equal(qom_name, "accel")) {
|
||||
return 0;
|
||||
}
|
||||
if (g_str_equal(qom_name, "igd-passthru")) {
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("xen"), qom_name, value,
|
||||
false);
|
||||
return 0;
|
||||
}
|
||||
if (g_str_equal(qom_name, "kvm-shadow-mem")) {
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value,
|
||||
false);
|
||||
return 0;
|
||||
}
|
||||
if (g_str_equal(qom_name, "kernel-irqchip")) {
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value,
|
||||
false);
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("whpx"), qom_name, value,
|
||||
false);
|
||||
return 0;
|
||||
value = qdict_get_try_str(qdict, "accel");
|
||||
if (value) {
|
||||
accelerators = g_strdup(value);
|
||||
qdict_del(qdict, "accel");
|
||||
}
|
||||
|
||||
return object_parse_property_opt(opaque, name, value, "type", errp);
|
||||
value = qdict_get_try_str(qdict, "igd-passthru");
|
||||
if (value) {
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("xen"), "igd-passthru", value,
|
||||
false);
|
||||
qdict_del(qdict, "igd-passthru");
|
||||
}
|
||||
|
||||
value = qdict_get_try_str(qdict, "kvm-shadow-mem");
|
||||
if (value) {
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), "kvm-shadow-mem", value,
|
||||
false);
|
||||
qdict_del(qdict, "kvm-shadow-mem");
|
||||
}
|
||||
|
||||
value = qdict_get_try_str(qdict, "kernel-irqchip");
|
||||
if (value) {
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), "kernel-irqchip", value,
|
||||
false);
|
||||
object_register_sugar_prop(ACCEL_CLASS_NAME("whpx"), "kernel-irqchip", value,
|
||||
false);
|
||||
qdict_del(qdict, "kernel-irqchip");
|
||||
}
|
||||
}
|
||||
|
||||
static void object_option_foreach_add(bool (*type_opt_predicate)(const char *))
|
||||
|
@ -1824,16 +1821,14 @@ static bool object_create_early(const char *type)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void qemu_apply_machine_options(void)
|
||||
static void qemu_apply_machine_options(QDict *qdict)
|
||||
{
|
||||
MachineClass *machine_class = MACHINE_GET_CLASS(current_machine);
|
||||
QemuOpts *machine_opts = qemu_get_machine_opts();
|
||||
const char *boot_order = NULL;
|
||||
const char *boot_once = NULL;
|
||||
QemuOpts *opts;
|
||||
|
||||
qemu_opt_foreach(machine_opts, machine_set_property, current_machine,
|
||||
&error_fatal);
|
||||
object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal);
|
||||
current_machine->ram_size = ram_size;
|
||||
current_machine->maxram_size = maxram_size;
|
||||
current_machine->ram_slots = ram_slots;
|
||||
|
@ -1862,10 +1857,14 @@ static void qemu_apply_machine_options(void)
|
|||
current_machine->boot_once = boot_once;
|
||||
|
||||
if (semihosting_enabled() && !semihosting_get_argc()) {
|
||||
const char *kernel_filename = qemu_opt_get(machine_opts, "kernel");
|
||||
const char *kernel_cmdline = qemu_opt_get(machine_opts, "append") ?: "";
|
||||
/* fall back to the -kernel/-append */
|
||||
semihosting_arg_fallback(kernel_filename, kernel_cmdline);
|
||||
semihosting_arg_fallback(current_machine->kernel_filename, current_machine->kernel_cmdline);
|
||||
}
|
||||
|
||||
if (current_machine->smp.cpus > 1) {
|
||||
Error *blocker = NULL;
|
||||
error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp");
|
||||
replay_add_blocker(blocker);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1921,8 +1920,7 @@ static void qemu_create_early_backends(void)
|
|||
|
||||
/*
|
||||
* Note: we need to create audio and block backends before
|
||||
* machine_set_property(), so machine properties can refer to
|
||||
* them.
|
||||
* setting machine properties, so they can be referred to.
|
||||
*/
|
||||
configure_blockdev(&bdo_queue, machine_class, snapshot);
|
||||
audio_init_audiodevs();
|
||||
|
@ -2088,16 +2086,14 @@ static void set_memory_options(MachineClass *mc)
|
|||
loc_pop(&loc);
|
||||
}
|
||||
|
||||
static void qemu_create_machine(MachineClass *machine_class)
|
||||
static void qemu_create_machine(QDict *qdict)
|
||||
{
|
||||
MachineClass *machine_class = select_machine(qdict, &error_fatal);
|
||||
object_set_machine_compat_props(machine_class->compat_props);
|
||||
|
||||
set_memory_options(machine_class);
|
||||
|
||||
current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));
|
||||
if (machine_help_func(qemu_get_machine_opts(), current_machine)) {
|
||||
exit(0);
|
||||
}
|
||||
object_property_add_child(object_get_root(), "machine",
|
||||
OBJECT(current_machine));
|
||||
object_property_add_child(container_get(OBJECT(current_machine),
|
||||
|
@ -2120,16 +2116,17 @@ static void qemu_create_machine(MachineClass *machine_class)
|
|||
qemu_set_hw_version(machine_class->hw_version);
|
||||
}
|
||||
|
||||
machine_smp_parse(current_machine,
|
||||
qemu_opts_find(qemu_find_opts("smp-opts"), NULL), &error_fatal);
|
||||
|
||||
/*
|
||||
* Get the default machine options from the machine if it is not already
|
||||
* specified either by the configuration file or by the command line.
|
||||
*/
|
||||
if (machine_class->default_machine_opts) {
|
||||
qemu_opts_set_defaults(qemu_find_opts("machine"),
|
||||
machine_class->default_machine_opts, 0);
|
||||
QDict *default_opts =
|
||||
keyval_parse(machine_class->default_machine_opts, NULL, NULL,
|
||||
&error_abort);
|
||||
object_set_properties_from_keyval(OBJECT(current_machine), default_opts,
|
||||
false, &error_abort);
|
||||
qobject_unref(default_opts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2151,7 +2148,8 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
|
|||
*/
|
||||
static bool is_qemuopts_group(const char *group)
|
||||
{
|
||||
if (g_str_equal(group, "object")) {
|
||||
if (g_str_equal(group, "object") ||
|
||||
g_str_equal(group, "machine")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -2164,6 +2162,13 @@ static void qemu_record_config_group(const char *group, QDict *dict,
|
|||
Visitor *v = qobject_input_visitor_new_keyval(QOBJECT(dict));
|
||||
object_option_add_visitor(v);
|
||||
visit_free(v);
|
||||
} else if (g_str_equal(group, "machine")) {
|
||||
/*
|
||||
* Cannot merge string-valued and type-safe dictionaries, so JSON
|
||||
* is not accepted yet for -M.
|
||||
*/
|
||||
assert(!from_json);
|
||||
keyval_merge(machine_opts_dict, dict, errp);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
@ -2294,13 +2299,11 @@ static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp)
|
|||
|
||||
static void configure_accelerators(const char *progname)
|
||||
{
|
||||
const char *accelerators;
|
||||
bool init_failed = false;
|
||||
|
||||
qemu_opts_foreach(qemu_find_opts("icount"),
|
||||
do_configure_icount, NULL, &error_fatal);
|
||||
|
||||
accelerators = qemu_opt_get(qemu_get_machine_opts(), "accel");
|
||||
if (QTAILQ_EMPTY(&qemu_accel_opts.head)) {
|
||||
char **accel_list, **tmp;
|
||||
|
||||
|
@ -2388,12 +2391,11 @@ static void create_default_memdev(MachineState *ms, const char *path)
|
|||
&error_fatal);
|
||||
}
|
||||
|
||||
static void qemu_validate_options(void)
|
||||
static void qemu_validate_options(const QDict *machine_opts)
|
||||
{
|
||||
QemuOpts *machine_opts = qemu_get_machine_opts();
|
||||
const char *kernel_filename = qemu_opt_get(machine_opts, "kernel");
|
||||
const char *initrd_filename = qemu_opt_get(machine_opts, "initrd");
|
||||
const char *kernel_cmdline = qemu_opt_get(machine_opts, "append");
|
||||
const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel");
|
||||
const char *initrd_filename = qdict_get_try_str(machine_opts, "initrd");
|
||||
const char *kernel_cmdline = qdict_get_try_str(machine_opts, "append");
|
||||
|
||||
if (kernel_filename == NULL) {
|
||||
if (kernel_cmdline != NULL) {
|
||||
|
@ -2733,7 +2735,6 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
qemu_add_opts(&qemu_trace_opts);
|
||||
qemu_plugin_add_opts();
|
||||
qemu_add_opts(&qemu_option_rom_opts);
|
||||
qemu_add_opts(&qemu_machine_opts);
|
||||
qemu_add_opts(&qemu_accel_opts);
|
||||
qemu_add_opts(&qemu_mem_opts);
|
||||
qemu_add_opts(&qemu_smp_opts);
|
||||
|
@ -2774,6 +2775,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
}
|
||||
}
|
||||
|
||||
machine_opts_dict = qdict_new();
|
||||
if (userconfig) {
|
||||
qemu_read_default_config_file(&error_fatal);
|
||||
}
|
||||
|
@ -2863,8 +2865,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
parse_display(optarg);
|
||||
break;
|
||||
case QEMU_OPTION_nographic:
|
||||
olist = qemu_find_opts("machine");
|
||||
qemu_opts_parse_noisily(olist, "graphics=off", false);
|
||||
qdict_put_str(machine_opts_dict, "graphics", "off");
|
||||
nographic = true;
|
||||
dpy.type = DISPLAY_TYPE_NONE;
|
||||
break;
|
||||
|
@ -2888,16 +2889,16 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
}
|
||||
break;
|
||||
case QEMU_OPTION_kernel:
|
||||
qemu_opts_set(qemu_find_opts("machine"), "kernel", optarg, &error_abort);
|
||||
qdict_put_str(machine_opts_dict, "kernel", optarg);
|
||||
break;
|
||||
case QEMU_OPTION_initrd:
|
||||
qemu_opts_set(qemu_find_opts("machine"), "initrd", optarg, &error_abort);
|
||||
qdict_put_str(machine_opts_dict, "initrd", optarg);
|
||||
break;
|
||||
case QEMU_OPTION_append:
|
||||
qemu_opts_set(qemu_find_opts("machine"), "append", optarg, &error_abort);
|
||||
qdict_put_str(machine_opts_dict, "append", optarg);
|
||||
break;
|
||||
case QEMU_OPTION_dtb:
|
||||
qemu_opts_set(qemu_find_opts("machine"), "dtb", optarg, &error_abort);
|
||||
qdict_put_str(machine_opts_dict, "dtb", optarg);
|
||||
break;
|
||||
case QEMU_OPTION_cdrom:
|
||||
drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
|
||||
|
@ -3007,7 +3008,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
}
|
||||
break;
|
||||
case QEMU_OPTION_bios:
|
||||
qemu_opts_set(qemu_find_opts("machine"), "firmware", optarg, &error_abort);
|
||||
qdict_put_str(machine_opts_dict, "firmware", optarg);
|
||||
break;
|
||||
case QEMU_OPTION_singlestep:
|
||||
singlestep = 1;
|
||||
|
@ -3234,6 +3235,8 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
case QEMU_OPTION_no_quit:
|
||||
dpy.has_window_close = true;
|
||||
dpy.window_close = false;
|
||||
warn_report("-no-quit is deprecated, please use "
|
||||
"-display ...,window-close=off instead.");
|
||||
break;
|
||||
case QEMU_OPTION_sdl:
|
||||
#ifdef CONFIG_SDL
|
||||
|
@ -3276,17 +3279,20 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
preconfig_requested = true;
|
||||
break;
|
||||
case QEMU_OPTION_enable_kvm:
|
||||
olist = qemu_find_opts("machine");
|
||||
qemu_opts_parse_noisily(olist, "accel=kvm", false);
|
||||
qdict_put_str(machine_opts_dict, "accel", "kvm");
|
||||
break;
|
||||
case QEMU_OPTION_M:
|
||||
case QEMU_OPTION_machine:
|
||||
olist = qemu_find_opts("machine");
|
||||
opts = qemu_opts_parse_noisily(olist, optarg, true);
|
||||
if (!opts) {
|
||||
exit(1);
|
||||
{
|
||||
bool help;
|
||||
|
||||
keyval_parse_into(machine_opts_dict, optarg, "type", &help, &error_fatal);
|
||||
if (help) {
|
||||
machine_help_func(machine_opts_dict);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case QEMU_OPTION_accel:
|
||||
accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"),
|
||||
optarg, true);
|
||||
|
@ -3313,12 +3319,10 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
}
|
||||
break;
|
||||
case QEMU_OPTION_usb:
|
||||
olist = qemu_find_opts("machine");
|
||||
qemu_opts_parse_noisily(olist, "usb=on", false);
|
||||
qdict_put_str(machine_opts_dict, "usb", "on");
|
||||
break;
|
||||
case QEMU_OPTION_usbdevice:
|
||||
olist = qemu_find_opts("machine");
|
||||
qemu_opts_parse_noisily(olist, "usb=on", false);
|
||||
qdict_put_str(machine_opts_dict, "usb", "on");
|
||||
add_device_config(DEV_USB, optarg);
|
||||
break;
|
||||
case QEMU_OPTION_device:
|
||||
|
@ -3328,21 +3332,16 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
}
|
||||
break;
|
||||
case QEMU_OPTION_smp:
|
||||
if (!qemu_opts_parse_noisily(qemu_find_opts("smp-opts"),
|
||||
optarg, true)) {
|
||||
exit(1);
|
||||
}
|
||||
machine_parse_property_opt(qemu_find_opts("smp-opts"), "smp", optarg, &error_fatal);
|
||||
break;
|
||||
case QEMU_OPTION_vnc:
|
||||
vnc_parse(optarg);
|
||||
break;
|
||||
case QEMU_OPTION_no_acpi:
|
||||
olist = qemu_find_opts("machine");
|
||||
qemu_opts_parse_noisily(olist, "acpi=off", false);
|
||||
qdict_put_str(machine_opts_dict, "acpi", "off");
|
||||
break;
|
||||
case QEMU_OPTION_no_hpet:
|
||||
olist = qemu_find_opts("machine");
|
||||
qemu_opts_parse_noisily(olist, "hpet=off", false);
|
||||
qdict_put_str(machine_opts_dict, "hpet", "off");
|
||||
break;
|
||||
case QEMU_OPTION_no_reboot:
|
||||
olist = qemu_find_opts("action");
|
||||
|
@ -3595,7 +3594,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
*/
|
||||
loc_set_none();
|
||||
|
||||
qemu_validate_options();
|
||||
qemu_validate_options(machine_opts_dict);
|
||||
qemu_process_sugar_options();
|
||||
|
||||
/*
|
||||
|
@ -3628,7 +3627,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
|
||||
configure_rtc(qemu_find_opts_singleton("rtc"));
|
||||
|
||||
qemu_create_machine(select_machine());
|
||||
qemu_create_machine(machine_opts_dict);
|
||||
|
||||
suspend_mux_open();
|
||||
|
||||
|
@ -3636,12 +3635,14 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
qemu_create_default_devices();
|
||||
qemu_create_early_backends();
|
||||
|
||||
qemu_apply_machine_options();
|
||||
qemu_apply_legacy_machine_options(machine_opts_dict);
|
||||
qemu_apply_machine_options(machine_opts_dict);
|
||||
qobject_unref(machine_opts_dict);
|
||||
phase_advance(PHASE_MACHINE_CREATED);
|
||||
|
||||
/*
|
||||
* Note: uses machine properties such as kernel-irqchip, must run
|
||||
* after machine_set_property().
|
||||
* after qemu_apply_machine_options.
|
||||
*/
|
||||
configure_accelerators(argv[0]);
|
||||
phase_advance(PHASE_ACCEL_CREATED);
|
||||
|
|
|
@ -1304,53 +1304,37 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
|
|||
};
|
||||
#undef REGISTER
|
||||
|
||||
typedef struct ExtSaveArea {
|
||||
uint32_t feature, bits;
|
||||
uint32_t offset, size;
|
||||
} ExtSaveArea;
|
||||
|
||||
static const ExtSaveArea x86_ext_save_areas[] = {
|
||||
ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = {
|
||||
[XSTATE_FP_BIT] = {
|
||||
/* x87 FP state component is always enabled if XSAVE is supported */
|
||||
.feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE,
|
||||
/* x87 state is in the legacy region of the XSAVE area */
|
||||
.offset = 0,
|
||||
.size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader),
|
||||
},
|
||||
[XSTATE_SSE_BIT] = {
|
||||
/* SSE state component is always enabled if XSAVE is supported */
|
||||
.feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE,
|
||||
/* SSE state is in the legacy region of the XSAVE area */
|
||||
.offset = 0,
|
||||
.size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader),
|
||||
},
|
||||
[XSTATE_YMM_BIT] =
|
||||
{ .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
|
||||
.offset = offsetof(X86XSaveArea, avx_state),
|
||||
.size = sizeof(XSaveAVX) },
|
||||
[XSTATE_BNDREGS_BIT] =
|
||||
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
|
||||
.offset = offsetof(X86XSaveArea, bndreg_state),
|
||||
.size = sizeof(XSaveBNDREG) },
|
||||
[XSTATE_BNDCSR_BIT] =
|
||||
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
|
||||
.offset = offsetof(X86XSaveArea, bndcsr_state),
|
||||
.size = sizeof(XSaveBNDCSR) },
|
||||
[XSTATE_OPMASK_BIT] =
|
||||
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
||||
.offset = offsetof(X86XSaveArea, opmask_state),
|
||||
.size = sizeof(XSaveOpmask) },
|
||||
[XSTATE_ZMM_Hi256_BIT] =
|
||||
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
||||
.offset = offsetof(X86XSaveArea, zmm_hi256_state),
|
||||
.size = sizeof(XSaveZMM_Hi256) },
|
||||
[XSTATE_Hi16_ZMM_BIT] =
|
||||
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
|
||||
.offset = offsetof(X86XSaveArea, hi16_zmm_state),
|
||||
.size = sizeof(XSaveHi16_ZMM) },
|
||||
[XSTATE_PKRU_BIT] =
|
||||
{ .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU,
|
||||
.offset = offsetof(X86XSaveArea, pkru_state),
|
||||
.size = sizeof(XSavePKRU) },
|
||||
};
|
||||
|
||||
|
|
|
@ -1305,41 +1305,23 @@ typedef struct XSavePKRU {
|
|||
uint32_t padding;
|
||||
} XSavePKRU;
|
||||
|
||||
typedef struct X86XSaveArea {
|
||||
X86LegacyXSaveArea legacy;
|
||||
X86XSaveHeader header;
|
||||
|
||||
/* Extended save areas: */
|
||||
|
||||
/* AVX State: */
|
||||
XSaveAVX avx_state;
|
||||
uint8_t padding[960 - 576 - sizeof(XSaveAVX)];
|
||||
/* MPX State: */
|
||||
XSaveBNDREG bndreg_state;
|
||||
XSaveBNDCSR bndcsr_state;
|
||||
/* AVX-512 State: */
|
||||
XSaveOpmask opmask_state;
|
||||
XSaveZMM_Hi256 zmm_hi256_state;
|
||||
XSaveHi16_ZMM hi16_zmm_state;
|
||||
/* PKRU State: */
|
||||
XSavePKRU pkru_state;
|
||||
} X86XSaveArea;
|
||||
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, avx_state) != 0x240);
|
||||
QEMU_BUILD_BUG_ON(sizeof(XSaveAVX) != 0x100);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, bndreg_state) != 0x3c0);
|
||||
QEMU_BUILD_BUG_ON(sizeof(XSaveBNDREG) != 0x40);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, bndcsr_state) != 0x400);
|
||||
QEMU_BUILD_BUG_ON(sizeof(XSaveBNDCSR) != 0x40);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, opmask_state) != 0x440);
|
||||
QEMU_BUILD_BUG_ON(sizeof(XSaveOpmask) != 0x40);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, zmm_hi256_state) != 0x480);
|
||||
QEMU_BUILD_BUG_ON(sizeof(XSaveZMM_Hi256) != 0x200);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, hi16_zmm_state) != 0x680);
|
||||
QEMU_BUILD_BUG_ON(sizeof(XSaveHi16_ZMM) != 0x400);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, pkru_state) != 0xA80);
|
||||
QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8);
|
||||
|
||||
typedef struct ExtSaveArea {
|
||||
uint32_t feature, bits;
|
||||
uint32_t offset, size;
|
||||
} ExtSaveArea;
|
||||
|
||||
#define XSAVE_STATE_AREA_COUNT (XSTATE_PKRU_BIT + 1)
|
||||
|
||||
extern ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT];
|
||||
|
||||
typedef enum TPRAccess {
|
||||
TPR_ACCESS_READ,
|
||||
TPR_ACCESS_WRITE,
|
||||
|
@ -1637,6 +1619,7 @@ typedef struct CPUX86State {
|
|||
uint64_t apic_bus_freq;
|
||||
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
|
||||
void *xsave_buf;
|
||||
uint32_t xsave_buf_len;
|
||||
#endif
|
||||
#if defined(CONFIG_KVM)
|
||||
struct kvm_nested_state *nested_state;
|
||||
|
@ -2197,8 +2180,8 @@ void x86_cpu_dump_local_apic_state(CPUState *cs, int flags);
|
|||
/* cpu.c */
|
||||
bool cpu_is_bsp(X86CPU *cpu);
|
||||
|
||||
void x86_cpu_xrstor_all_areas(X86CPU *cpu, const X86XSaveArea *buf);
|
||||
void x86_cpu_xsave_all_areas(X86CPU *cpu, X86XSaveArea *buf);
|
||||
void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen);
|
||||
void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen);
|
||||
void x86_update_hflags(CPUX86State* env);
|
||||
|
||||
static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat)
|
||||
|
|
|
@ -30,6 +30,33 @@ static void hvf_cpu_max_instance_init(X86CPU *cpu)
|
|||
hvf_get_supported_cpuid(0xC0000000, 0, R_EAX);
|
||||
}
|
||||
|
||||
static void hvf_cpu_xsave_init(void)
|
||||
{
|
||||
static bool first = true;
|
||||
int i;
|
||||
|
||||
if (!first) {
|
||||
return;
|
||||
}
|
||||
first = false;
|
||||
|
||||
/* x87 and SSE states are in the legacy region of the XSAVE area. */
|
||||
x86_ext_save_areas[XSTATE_FP_BIT].offset = 0;
|
||||
x86_ext_save_areas[XSTATE_SSE_BIT].offset = 0;
|
||||
|
||||
for (i = XSTATE_SSE_BIT + 1; i < XSAVE_STATE_AREA_COUNT; i++) {
|
||||
ExtSaveArea *esa = &x86_ext_save_areas[i];
|
||||
|
||||
if (esa->size) {
|
||||
int sz = hvf_get_supported_cpuid(0xd, i, R_EAX);
|
||||
if (sz != 0) {
|
||||
assert(esa->size == sz);
|
||||
esa->offset = hvf_get_supported_cpuid(0xd, i, R_EBX);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hvf_cpu_instance_init(CPUState *cs)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
|
@ -42,6 +69,8 @@ static void hvf_cpu_instance_init(CPUState *cs)
|
|||
if (cpu->max_features) {
|
||||
hvf_cpu_max_instance_init(cpu);
|
||||
}
|
||||
|
||||
hvf_cpu_xsave_init();
|
||||
}
|
||||
|
||||
static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -267,7 +267,14 @@ int hvf_arch_init_vcpu(CPUState *cpu)
|
|||
wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, 0);
|
||||
|
||||
x86cpu = X86_CPU(cpu);
|
||||
x86cpu->env.xsave_buf = qemu_memalign(4096, 4096);
|
||||
x86cpu->env.xsave_buf_len = 4096;
|
||||
x86cpu->env.xsave_buf = qemu_memalign(4096, x86cpu->env.xsave_buf_len);
|
||||
|
||||
/*
|
||||
* The allocated storage must be large enough for all of the
|
||||
* possible XSAVE state components.
|
||||
*/
|
||||
assert(hvf_get_supported_cpuid(0xd, 0, R_ECX) <= x86cpu->env.xsave_buf_len);
|
||||
|
||||
hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_STAR, 1);
|
||||
hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_LSTAR, 1);
|
||||
|
|
|
@ -73,14 +73,12 @@ void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg)
|
|||
|
||||
void hvf_put_xsave(CPUState *cpu_state)
|
||||
{
|
||||
void *xsave = X86_CPU(cpu_state)->env.xsave_buf;
|
||||
uint32_t xsave_len = X86_CPU(cpu_state)->env.xsave_buf_len;
|
||||
|
||||
struct X86XSaveArea *xsave;
|
||||
x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave, xsave_len);
|
||||
|
||||
xsave = X86_CPU(cpu_state)->env.xsave_buf;
|
||||
|
||||
x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave);
|
||||
|
||||
if (hv_vcpu_write_fpstate(cpu_state->hvf->fd, (void*)xsave, 4096)) {
|
||||
if (hv_vcpu_write_fpstate(cpu_state->hvf->fd, xsave, xsave_len)) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
@ -158,15 +156,14 @@ void hvf_put_msrs(CPUState *cpu_state)
|
|||
|
||||
void hvf_get_xsave(CPUState *cpu_state)
|
||||
{
|
||||
struct X86XSaveArea *xsave;
|
||||
void *xsave = X86_CPU(cpu_state)->env.xsave_buf;
|
||||
uint32_t xsave_len = X86_CPU(cpu_state)->env.xsave_buf_len;
|
||||
|
||||
xsave = X86_CPU(cpu_state)->env.xsave_buf;
|
||||
|
||||
if (hv_vcpu_read_fpstate(cpu_state->hvf->fd, (void*)xsave, 4096)) {
|
||||
if (hv_vcpu_read_fpstate(cpu_state->hvf->fd, xsave, xsave_len)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
x86_cpu_xrstor_all_areas(X86_CPU(cpu_state), xsave);
|
||||
x86_cpu_xrstor_all_areas(X86_CPU(cpu_state), xsave, xsave_len);
|
||||
}
|
||||
|
||||
void hvf_get_segments(CPUState *cpu_state)
|
||||
|
|
|
@ -122,6 +122,34 @@ static void kvm_cpu_max_instance_init(X86CPU *cpu)
|
|||
kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
|
||||
}
|
||||
|
||||
static void kvm_cpu_xsave_init(void)
|
||||
{
|
||||
static bool first = true;
|
||||
KVMState *s = kvm_state;
|
||||
int i;
|
||||
|
||||
if (!first) {
|
||||
return;
|
||||
}
|
||||
first = false;
|
||||
|
||||
/* x87 and SSE states are in the legacy region of the XSAVE area. */
|
||||
x86_ext_save_areas[XSTATE_FP_BIT].offset = 0;
|
||||
x86_ext_save_areas[XSTATE_SSE_BIT].offset = 0;
|
||||
|
||||
for (i = XSTATE_SSE_BIT + 1; i < XSAVE_STATE_AREA_COUNT; i++) {
|
||||
ExtSaveArea *esa = &x86_ext_save_areas[i];
|
||||
|
||||
if (esa->size) {
|
||||
int sz = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EAX);
|
||||
if (sz != 0) {
|
||||
assert(esa->size == sz);
|
||||
esa->offset = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EBX);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_cpu_instance_init(CPUState *cs)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
|
@ -141,6 +169,8 @@ static void kvm_cpu_instance_init(CPUState *cs)
|
|||
if (cpu->max_features) {
|
||||
kvm_cpu_max_instance_init(cpu);
|
||||
}
|
||||
|
||||
kvm_cpu_xsave_init();
|
||||
}
|
||||
|
||||
static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -1888,8 +1888,16 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
|||
}
|
||||
|
||||
if (has_xsave) {
|
||||
env->xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave));
|
||||
memset(env->xsave_buf, 0, sizeof(struct kvm_xsave));
|
||||
env->xsave_buf_len = sizeof(struct kvm_xsave);
|
||||
env->xsave_buf = qemu_memalign(4096, env->xsave_buf_len);
|
||||
memset(env->xsave_buf, 0, env->xsave_buf_len);
|
||||
|
||||
/*
|
||||
* The allocated storage must be large enough for all of the
|
||||
* possible XSAVE state components.
|
||||
*/
|
||||
assert(kvm_arch_get_supported_cpuid(kvm_state, 0xd, 0, R_ECX)
|
||||
<= env->xsave_buf_len);
|
||||
}
|
||||
|
||||
max_nested_state_len = kvm_max_nested_state_length();
|
||||
|
@ -2466,54 +2474,15 @@ static int kvm_put_fpu(X86CPU *cpu)
|
|||
return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_FPU, &fpu);
|
||||
}
|
||||
|
||||
#define XSAVE_FCW_FSW 0
|
||||
#define XSAVE_FTW_FOP 1
|
||||
#define XSAVE_CWD_RIP 2
|
||||
#define XSAVE_CWD_RDP 4
|
||||
#define XSAVE_MXCSR 6
|
||||
#define XSAVE_ST_SPACE 8
|
||||
#define XSAVE_XMM_SPACE 40
|
||||
#define XSAVE_XSTATE_BV 128
|
||||
#define XSAVE_YMMH_SPACE 144
|
||||
#define XSAVE_BNDREGS 240
|
||||
#define XSAVE_BNDCSR 256
|
||||
#define XSAVE_OPMASK 272
|
||||
#define XSAVE_ZMM_Hi256 288
|
||||
#define XSAVE_Hi16_ZMM 416
|
||||
#define XSAVE_PKRU 672
|
||||
|
||||
#define XSAVE_BYTE_OFFSET(word_offset) \
|
||||
((word_offset) * sizeof_field(struct kvm_xsave, region[0]))
|
||||
|
||||
#define ASSERT_OFFSET(word_offset, field) \
|
||||
QEMU_BUILD_BUG_ON(XSAVE_BYTE_OFFSET(word_offset) != \
|
||||
offsetof(X86XSaveArea, field))
|
||||
|
||||
ASSERT_OFFSET(XSAVE_FCW_FSW, legacy.fcw);
|
||||
ASSERT_OFFSET(XSAVE_FTW_FOP, legacy.ftw);
|
||||
ASSERT_OFFSET(XSAVE_CWD_RIP, legacy.fpip);
|
||||
ASSERT_OFFSET(XSAVE_CWD_RDP, legacy.fpdp);
|
||||
ASSERT_OFFSET(XSAVE_MXCSR, legacy.mxcsr);
|
||||
ASSERT_OFFSET(XSAVE_ST_SPACE, legacy.fpregs);
|
||||
ASSERT_OFFSET(XSAVE_XMM_SPACE, legacy.xmm_regs);
|
||||
ASSERT_OFFSET(XSAVE_XSTATE_BV, header.xstate_bv);
|
||||
ASSERT_OFFSET(XSAVE_YMMH_SPACE, avx_state);
|
||||
ASSERT_OFFSET(XSAVE_BNDREGS, bndreg_state);
|
||||
ASSERT_OFFSET(XSAVE_BNDCSR, bndcsr_state);
|
||||
ASSERT_OFFSET(XSAVE_OPMASK, opmask_state);
|
||||
ASSERT_OFFSET(XSAVE_ZMM_Hi256, zmm_hi256_state);
|
||||
ASSERT_OFFSET(XSAVE_Hi16_ZMM, hi16_zmm_state);
|
||||
ASSERT_OFFSET(XSAVE_PKRU, pkru_state);
|
||||
|
||||
static int kvm_put_xsave(X86CPU *cpu)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
X86XSaveArea *xsave = env->xsave_buf;
|
||||
void *xsave = env->xsave_buf;
|
||||
|
||||
if (!has_xsave) {
|
||||
return kvm_put_fpu(cpu);
|
||||
}
|
||||
x86_cpu_xsave_all_areas(cpu, xsave);
|
||||
x86_cpu_xsave_all_areas(cpu, xsave, env->xsave_buf_len);
|
||||
|
||||
return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XSAVE, xsave);
|
||||
}
|
||||
|
@ -3158,7 +3127,7 @@ static int kvm_get_fpu(X86CPU *cpu)
|
|||
static int kvm_get_xsave(X86CPU *cpu)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
X86XSaveArea *xsave = env->xsave_buf;
|
||||
void *xsave = env->xsave_buf;
|
||||
int ret;
|
||||
|
||||
if (!has_xsave) {
|
||||
|
@ -3169,7 +3138,7 @@ static int kvm_get_xsave(X86CPU *cpu)
|
|||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
x86_cpu_xrstor_all_areas(cpu, xsave);
|
||||
x86_cpu_xrstor_all_areas(cpu, xsave, env->xsave_buf_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include <math.h>
|
||||
#include "cpu.h"
|
||||
#include "tcg-cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "fpu/softfloat.h"
|
||||
#include "fpu/softfloat-macros.h"
|
||||
|
|
|
@ -80,6 +80,24 @@ static void tcg_cpu_class_init(CPUClass *cc)
|
|||
cc->init_accel_cpu = tcg_cpu_init_ops;
|
||||
}
|
||||
|
||||
static void tcg_cpu_xsave_init(void)
|
||||
{
|
||||
#define XO(bit, field) \
|
||||
x86_ext_save_areas[bit].offset = offsetof(X86XSaveArea, field);
|
||||
|
||||
XO(XSTATE_FP_BIT, legacy);
|
||||
XO(XSTATE_SSE_BIT, legacy);
|
||||
XO(XSTATE_YMM_BIT, avx_state);
|
||||
XO(XSTATE_BNDREGS_BIT, bndreg_state);
|
||||
XO(XSTATE_BNDCSR_BIT, bndcsr_state);
|
||||
XO(XSTATE_OPMASK_BIT, opmask_state);
|
||||
XO(XSTATE_ZMM_Hi256_BIT, zmm_hi256_state);
|
||||
XO(XSTATE_Hi16_ZMM_BIT, hi16_zmm_state);
|
||||
XO(XSTATE_PKRU_BIT, pkru_state);
|
||||
|
||||
#undef XO
|
||||
}
|
||||
|
||||
/*
|
||||
* TCG-specific defaults that override all CPU models when using TCG
|
||||
*/
|
||||
|
@ -93,6 +111,8 @@ static void tcg_cpu_instance_init(CPUState *cs)
|
|||
X86CPU *cpu = X86_CPU(cs);
|
||||
/* Special cases not set in the X86CPUDefinition structs: */
|
||||
x86_cpu_apply_props(cpu, tcg_default_props);
|
||||
|
||||
tcg_cpu_xsave_init();
|
||||
}
|
||||
|
||||
static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -19,6 +19,63 @@
|
|||
#ifndef TCG_CPU_H
|
||||
#define TCG_CPU_H
|
||||
|
||||
#define XSAVE_FCW_FSW_OFFSET 0x000
|
||||
#define XSAVE_FTW_FOP_OFFSET 0x004
|
||||
#define XSAVE_CWD_RIP_OFFSET 0x008
|
||||
#define XSAVE_CWD_RDP_OFFSET 0x010
|
||||
#define XSAVE_MXCSR_OFFSET 0x018
|
||||
#define XSAVE_ST_SPACE_OFFSET 0x020
|
||||
#define XSAVE_XMM_SPACE_OFFSET 0x0a0
|
||||
#define XSAVE_XSTATE_BV_OFFSET 0x200
|
||||
#define XSAVE_AVX_OFFSET 0x240
|
||||
#define XSAVE_BNDREG_OFFSET 0x3c0
|
||||
#define XSAVE_BNDCSR_OFFSET 0x400
|
||||
#define XSAVE_OPMASK_OFFSET 0x440
|
||||
#define XSAVE_ZMM_HI256_OFFSET 0x480
|
||||
#define XSAVE_HI16_ZMM_OFFSET 0x680
|
||||
#define XSAVE_PKRU_OFFSET 0xa80
|
||||
|
||||
typedef struct X86XSaveArea {
|
||||
X86LegacyXSaveArea legacy;
|
||||
X86XSaveHeader header;
|
||||
|
||||
/* Extended save areas: */
|
||||
|
||||
/* AVX State: */
|
||||
XSaveAVX avx_state;
|
||||
|
||||
/* Ensure that XSaveBNDREG is properly aligned. */
|
||||
uint8_t padding[XSAVE_BNDREG_OFFSET
|
||||
- sizeof(X86LegacyXSaveArea)
|
||||
- sizeof(X86XSaveHeader)
|
||||
- sizeof(XSaveAVX)];
|
||||
|
||||
/* MPX State: */
|
||||
XSaveBNDREG bndreg_state;
|
||||
XSaveBNDCSR bndcsr_state;
|
||||
/* AVX-512 State: */
|
||||
XSaveOpmask opmask_state;
|
||||
XSaveZMM_Hi256 zmm_hi256_state;
|
||||
XSaveHi16_ZMM hi16_zmm_state;
|
||||
/* PKRU State: */
|
||||
XSavePKRU pkru_state;
|
||||
} X86XSaveArea;
|
||||
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.fcw) != XSAVE_FCW_FSW_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.ftw) != XSAVE_FTW_FOP_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.fpip) != XSAVE_CWD_RIP_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.fpdp) != XSAVE_CWD_RDP_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.mxcsr) != XSAVE_MXCSR_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.fpregs) != XSAVE_ST_SPACE_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.xmm_regs) != XSAVE_XMM_SPACE_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, avx_state) != XSAVE_AVX_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, bndreg_state) != XSAVE_BNDREG_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, bndcsr_state) != XSAVE_BNDCSR_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, opmask_state) != XSAVE_OPMASK_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, zmm_hi256_state) != XSAVE_ZMM_HI256_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, hi16_zmm_state) != XSAVE_HI16_ZMM_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, pkru_state) != XSAVE_PKRU_OFFSET);
|
||||
|
||||
bool tcg_cpu_realizefn(CPUState *cs, Error **errp);
|
||||
|
||||
#endif /* TCG_CPU_H */
|
||||
|
|
|
@ -6,14 +6,23 @@
|
|||
|
||||
#include "cpu.h"
|
||||
|
||||
void x86_cpu_xsave_all_areas(X86CPU *cpu, X86XSaveArea *buf)
|
||||
void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
X86XSaveArea *xsave = buf;
|
||||
|
||||
uint16_t cwd, swd, twd;
|
||||
const ExtSaveArea *e, *f;
|
||||
int i;
|
||||
memset(xsave, 0, sizeof(X86XSaveArea));
|
||||
|
||||
X86LegacyXSaveArea *legacy;
|
||||
X86XSaveHeader *header;
|
||||
uint16_t cwd, swd, twd;
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_FP_BIT];
|
||||
|
||||
legacy = buf + e->offset;
|
||||
header = buf + e->offset + sizeof(*legacy);
|
||||
|
||||
twd = 0;
|
||||
swd = env->fpus & ~(7 << 11);
|
||||
swd |= (env->fpstt & 7) << 11;
|
||||
|
@ -21,92 +30,222 @@ void x86_cpu_xsave_all_areas(X86CPU *cpu, X86XSaveArea *buf)
|
|||
for (i = 0; i < 8; ++i) {
|
||||
twd |= (!env->fptags[i]) << i;
|
||||
}
|
||||
xsave->legacy.fcw = cwd;
|
||||
xsave->legacy.fsw = swd;
|
||||
xsave->legacy.ftw = twd;
|
||||
xsave->legacy.fpop = env->fpop;
|
||||
xsave->legacy.fpip = env->fpip;
|
||||
xsave->legacy.fpdp = env->fpdp;
|
||||
memcpy(&xsave->legacy.fpregs, env->fpregs,
|
||||
sizeof env->fpregs);
|
||||
xsave->legacy.mxcsr = env->mxcsr;
|
||||
xsave->header.xstate_bv = env->xstate_bv;
|
||||
memcpy(&xsave->bndreg_state.bnd_regs, env->bnd_regs,
|
||||
sizeof env->bnd_regs);
|
||||
xsave->bndcsr_state.bndcsr = env->bndcs_regs;
|
||||
memcpy(&xsave->opmask_state.opmask_regs, env->opmask_regs,
|
||||
sizeof env->opmask_regs);
|
||||
legacy->fcw = cwd;
|
||||
legacy->fsw = swd;
|
||||
legacy->ftw = twd;
|
||||
legacy->fpop = env->fpop;
|
||||
legacy->fpip = env->fpip;
|
||||
legacy->fpdp = env->fpdp;
|
||||
memcpy(&legacy->fpregs, env->fpregs,
|
||||
sizeof(env->fpregs));
|
||||
legacy->mxcsr = env->mxcsr;
|
||||
|
||||
for (i = 0; i < CPU_NB_REGS; i++) {
|
||||
uint8_t *xmm = xsave->legacy.xmm_regs[i];
|
||||
uint8_t *ymmh = xsave->avx_state.ymmh[i];
|
||||
uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
|
||||
uint8_t *xmm = legacy->xmm_regs[i];
|
||||
|
||||
stq_p(xmm, env->xmm_regs[i].ZMM_Q(0));
|
||||
stq_p(xmm+8, env->xmm_regs[i].ZMM_Q(1));
|
||||
stq_p(ymmh, env->xmm_regs[i].ZMM_Q(2));
|
||||
stq_p(ymmh+8, env->xmm_regs[i].ZMM_Q(3));
|
||||
stq_p(zmmh, env->xmm_regs[i].ZMM_Q(4));
|
||||
stq_p(zmmh+8, env->xmm_regs[i].ZMM_Q(5));
|
||||
stq_p(zmmh+16, env->xmm_regs[i].ZMM_Q(6));
|
||||
stq_p(zmmh+24, env->xmm_regs[i].ZMM_Q(7));
|
||||
stq_p(xmm + 8, env->xmm_regs[i].ZMM_Q(1));
|
||||
}
|
||||
|
||||
header->xstate_bv = env->xstate_bv;
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_YMM_BIT];
|
||||
if (e->size && e->offset) {
|
||||
XSaveAVX *avx;
|
||||
|
||||
avx = buf + e->offset;
|
||||
|
||||
for (i = 0; i < CPU_NB_REGS; i++) {
|
||||
uint8_t *ymmh = avx->ymmh[i];
|
||||
|
||||
stq_p(ymmh, env->xmm_regs[i].ZMM_Q(2));
|
||||
stq_p(ymmh + 8, env->xmm_regs[i].ZMM_Q(3));
|
||||
}
|
||||
}
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
|
||||
if (e->size && e->offset) {
|
||||
XSaveBNDREG *bndreg;
|
||||
XSaveBNDCSR *bndcsr;
|
||||
|
||||
f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
|
||||
assert(f->size);
|
||||
assert(f->offset);
|
||||
|
||||
bndreg = buf + e->offset;
|
||||
bndcsr = buf + f->offset;
|
||||
|
||||
memcpy(&bndreg->bnd_regs, env->bnd_regs,
|
||||
sizeof(env->bnd_regs));
|
||||
bndcsr->bndcsr = env->bndcs_regs;
|
||||
}
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
|
||||
if (e->size && e->offset) {
|
||||
XSaveOpmask *opmask;
|
||||
XSaveZMM_Hi256 *zmm_hi256;
|
||||
#ifdef TARGET_X86_64
|
||||
XSaveHi16_ZMM *hi16_zmm;
|
||||
#endif
|
||||
|
||||
f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
|
||||
assert(f->size);
|
||||
assert(f->offset);
|
||||
|
||||
opmask = buf + e->offset;
|
||||
zmm_hi256 = buf + f->offset;
|
||||
|
||||
memcpy(&opmask->opmask_regs, env->opmask_regs,
|
||||
sizeof(env->opmask_regs));
|
||||
|
||||
for (i = 0; i < CPU_NB_REGS; i++) {
|
||||
uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
|
||||
|
||||
stq_p(zmmh, env->xmm_regs[i].ZMM_Q(4));
|
||||
stq_p(zmmh + 8, env->xmm_regs[i].ZMM_Q(5));
|
||||
stq_p(zmmh + 16, env->xmm_regs[i].ZMM_Q(6));
|
||||
stq_p(zmmh + 24, env->xmm_regs[i].ZMM_Q(7));
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
|
||||
assert(f->size);
|
||||
assert(f->offset);
|
||||
|
||||
hi16_zmm = buf + f->offset;
|
||||
|
||||
memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16],
|
||||
16 * sizeof(env->xmm_regs[16]));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
memcpy(&xsave->hi16_zmm_state.hi16_zmm, &env->xmm_regs[16],
|
||||
16 * sizeof env->xmm_regs[16]);
|
||||
memcpy(&xsave->pkru_state, &env->pkru, sizeof env->pkru);
|
||||
#endif
|
||||
e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
|
||||
if (e->size && e->offset) {
|
||||
XSavePKRU *pkru = buf + e->offset;
|
||||
|
||||
memcpy(pkru, &env->pkru, sizeof(env->pkru));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void x86_cpu_xrstor_all_areas(X86CPU *cpu, const X86XSaveArea *buf)
|
||||
void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen)
|
||||
{
|
||||
|
||||
CPUX86State *env = &cpu->env;
|
||||
const X86XSaveArea *xsave = buf;
|
||||
|
||||
const ExtSaveArea *e, *f, *g;
|
||||
int i;
|
||||
|
||||
const X86LegacyXSaveArea *legacy;
|
||||
const X86XSaveHeader *header;
|
||||
uint16_t cwd, swd, twd;
|
||||
cwd = xsave->legacy.fcw;
|
||||
swd = xsave->legacy.fsw;
|
||||
twd = xsave->legacy.ftw;
|
||||
env->fpop = xsave->legacy.fpop;
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_FP_BIT];
|
||||
|
||||
legacy = buf + e->offset;
|
||||
header = buf + e->offset + sizeof(*legacy);
|
||||
|
||||
cwd = legacy->fcw;
|
||||
swd = legacy->fsw;
|
||||
twd = legacy->ftw;
|
||||
env->fpop = legacy->fpop;
|
||||
env->fpstt = (swd >> 11) & 7;
|
||||
env->fpus = swd;
|
||||
env->fpuc = cwd;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
env->fptags[i] = !((twd >> i) & 1);
|
||||
}
|
||||
env->fpip = xsave->legacy.fpip;
|
||||
env->fpdp = xsave->legacy.fpdp;
|
||||
env->mxcsr = xsave->legacy.mxcsr;
|
||||
memcpy(env->fpregs, &xsave->legacy.fpregs,
|
||||
sizeof env->fpregs);
|
||||
env->xstate_bv = xsave->header.xstate_bv;
|
||||
memcpy(env->bnd_regs, &xsave->bndreg_state.bnd_regs,
|
||||
sizeof env->bnd_regs);
|
||||
env->bndcs_regs = xsave->bndcsr_state.bndcsr;
|
||||
memcpy(env->opmask_regs, &xsave->opmask_state.opmask_regs,
|
||||
sizeof env->opmask_regs);
|
||||
env->fpip = legacy->fpip;
|
||||
env->fpdp = legacy->fpdp;
|
||||
env->mxcsr = legacy->mxcsr;
|
||||
memcpy(env->fpregs, &legacy->fpregs,
|
||||
sizeof(env->fpregs));
|
||||
|
||||
for (i = 0; i < CPU_NB_REGS; i++) {
|
||||
const uint8_t *xmm = xsave->legacy.xmm_regs[i];
|
||||
const uint8_t *ymmh = xsave->avx_state.ymmh[i];
|
||||
const uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
|
||||
const uint8_t *xmm = legacy->xmm_regs[i];
|
||||
|
||||
env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm);
|
||||
env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm+8);
|
||||
env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
|
||||
env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh+8);
|
||||
env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
|
||||
env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh+8);
|
||||
env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh+16);
|
||||
env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh+24);
|
||||
env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8);
|
||||
}
|
||||
|
||||
env->xstate_bv = header->xstate_bv;
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_YMM_BIT];
|
||||
if (e->size && e->offset) {
|
||||
const XSaveAVX *avx;
|
||||
|
||||
avx = buf + e->offset;
|
||||
for (i = 0; i < CPU_NB_REGS; i++) {
|
||||
const uint8_t *ymmh = avx->ymmh[i];
|
||||
|
||||
env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
|
||||
env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8);
|
||||
}
|
||||
}
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
|
||||
if (e->size && e->offset) {
|
||||
const XSaveBNDREG *bndreg;
|
||||
const XSaveBNDCSR *bndcsr;
|
||||
|
||||
f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
|
||||
assert(f->size);
|
||||
assert(f->offset);
|
||||
|
||||
bndreg = buf + e->offset;
|
||||
bndcsr = buf + f->offset;
|
||||
|
||||
memcpy(env->bnd_regs, &bndreg->bnd_regs,
|
||||
sizeof(env->bnd_regs));
|
||||
env->bndcs_regs = bndcsr->bndcsr;
|
||||
}
|
||||
|
||||
e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
|
||||
if (e->size && e->offset) {
|
||||
const XSaveOpmask *opmask;
|
||||
const XSaveZMM_Hi256 *zmm_hi256;
|
||||
#ifdef TARGET_X86_64
|
||||
const XSaveHi16_ZMM *hi16_zmm;
|
||||
#endif
|
||||
|
||||
f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
|
||||
assert(f->size);
|
||||
assert(f->offset);
|
||||
|
||||
g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
|
||||
assert(g->size);
|
||||
assert(g->offset);
|
||||
|
||||
opmask = buf + e->offset;
|
||||
zmm_hi256 = buf + f->offset;
|
||||
#ifdef TARGET_X86_64
|
||||
hi16_zmm = buf + g->offset;
|
||||
#endif
|
||||
|
||||
memcpy(env->opmask_regs, &opmask->opmask_regs,
|
||||
sizeof(env->opmask_regs));
|
||||
|
||||
for (i = 0; i < CPU_NB_REGS; i++) {
|
||||
const uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
|
||||
|
||||
env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
|
||||
env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8);
|
||||
env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16);
|
||||
env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24);
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm,
|
||||
16 * sizeof(env->xmm_regs[16]));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
memcpy(&env->xmm_regs[16], &xsave->hi16_zmm_state.hi16_zmm,
|
||||
16 * sizeof env->xmm_regs[16]);
|
||||
memcpy(&env->pkru, &xsave->pkru_state, sizeof env->pkru);
|
||||
#endif
|
||||
e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
|
||||
if (e->size && e->offset) {
|
||||
const XSavePKRU *pkru;
|
||||
|
||||
pkru = buf + e->offset;
|
||||
memcpy(&env->pkru, pkru, sizeof(env->pkru));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ static void test_mon_explicit(const void *data)
|
|||
g_autofree char *s = NULL;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-smp 8 -numa node,nodeid=0,memdev=ram,cpus=0-3 "
|
||||
cli = make_cli(data, "-machine smp.cpus=8 -numa node,nodeid=0,memdev=ram,cpus=0-3 "
|
||||
"-numa node,nodeid=1,cpus=4-7");
|
||||
qts = qtest_init(cli);
|
||||
|
||||
|
@ -42,7 +42,7 @@ static void test_def_cpu_split(const void *data)
|
|||
g_autofree char *s = NULL;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-smp 8 -numa node,memdev=ram -numa node");
|
||||
cli = make_cli(data, "-machine smp.cpus=8 -numa node,memdev=ram -numa node");
|
||||
qts = qtest_init(cli);
|
||||
|
||||
s = qtest_hmp(qts, "info numa");
|
||||
|
@ -58,7 +58,7 @@ static void test_mon_partial(const void *data)
|
|||
g_autofree char *s = NULL;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-smp 8 "
|
||||
cli = make_cli(data, "-machine smp.cpus=8 "
|
||||
"-numa node,nodeid=0,memdev=ram,cpus=0-1 "
|
||||
"-numa node,nodeid=1,cpus=4-5 ");
|
||||
qts = qtest_init(cli);
|
||||
|
@ -86,7 +86,7 @@ static void test_query_cpus(const void *data)
|
|||
QTestState *qts;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-smp 8 -numa node,memdev=ram,cpus=0-3 "
|
||||
cli = make_cli(data, "-machine smp.cpus=8 -numa node,memdev=ram,cpus=0-3 "
|
||||
"-numa node,cpus=4-7");
|
||||
qts = qtest_init(cli);
|
||||
cpus = get_cpus(qts, &resp);
|
||||
|
@ -124,7 +124,7 @@ static void pc_numa_cpu(const void *data)
|
|||
QTestState *qts;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-cpu pentium -smp 8,sockets=2,cores=2,threads=2 "
|
||||
cli = make_cli(data, "-cpu pentium -machine smp.cpus=8,smp.sockets=2,smp.cores=2,smp.threads=2 "
|
||||
"-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 "
|
||||
"-numa cpu,node-id=1,socket-id=0 "
|
||||
"-numa cpu,node-id=0,socket-id=1,core-id=0 "
|
||||
|
@ -177,7 +177,7 @@ static void spapr_numa_cpu(const void *data)
|
|||
QTestState *qts;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-smp 4,cores=4 "
|
||||
cli = make_cli(data, "-machine smp.cpus=4,smp.cores=4 "
|
||||
"-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 "
|
||||
"-numa cpu,node-id=0,core-id=0 "
|
||||
"-numa cpu,node-id=0,core-id=1 "
|
||||
|
@ -222,7 +222,7 @@ static void aarch64_numa_cpu(const void *data)
|
|||
QTestState *qts;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-smp 2 "
|
||||
cli = make_cli(data, "-machine smp.cpus=2 "
|
||||
"-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 "
|
||||
"-numa cpu,node-id=1,thread-id=0 "
|
||||
"-numa cpu,node-id=0,thread-id=1");
|
||||
|
@ -265,7 +265,7 @@ static void pc_dynamic_cpu_cfg(const void *data)
|
|||
QTestState *qs;
|
||||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-nodefaults --preconfig -smp 2");
|
||||
cli = make_cli(data, "-nodefaults --preconfig -machine smp.cpus=2");
|
||||
qs = qtest_init(cli);
|
||||
|
||||
/* create 2 numa nodes */
|
||||
|
@ -324,7 +324,7 @@ static void pc_hmat_build_cfg(const void *data)
|
|||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-nodefaults --preconfig -machine hmat=on "
|
||||
"-smp 2,sockets=2 "
|
||||
"-machine smp.cpus=2,smp.sockets=2 "
|
||||
"-m 128M,slots=2,maxmem=1G "
|
||||
"-object memory-backend-ram,size=64M,id=m0 "
|
||||
"-object memory-backend-ram,size=64M,id=m1 "
|
||||
|
@ -453,7 +453,7 @@ static void pc_hmat_off_cfg(const void *data)
|
|||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-nodefaults --preconfig "
|
||||
"-smp 2,sockets=2 "
|
||||
"-machine smp.cpus=2,smp.sockets=2 "
|
||||
"-m 128M,slots=2,maxmem=1G "
|
||||
"-object memory-backend-ram,size=64M,id=m0,prealloc=y "
|
||||
"-object memory-backend-ram,size=64M,id=m1 "
|
||||
|
@ -492,7 +492,7 @@ static void pc_hmat_erange_cfg(const void *data)
|
|||
g_autofree char *cli = NULL;
|
||||
|
||||
cli = make_cli(data, "-nodefaults --preconfig -machine hmat=on "
|
||||
"-smp 2,sockets=2 "
|
||||
"-machine smp.cpus=2,smp.sockets=2 "
|
||||
"-m 128M,slots=2,maxmem=1G "
|
||||
"-object memory-backend-ram,size=64M,id=m0 "
|
||||
"-object memory-backend-ram,size=64M,id=m1 "
|
||||
|
|
|
@ -747,6 +747,61 @@ static void test_keyval_visit_any(void)
|
|||
visit_free(v);
|
||||
}
|
||||
|
||||
static void test_keyval_merge_dict(void)
|
||||
{
|
||||
QDict *first = keyval_parse("opt1=abc,opt2.sub1=def,opt2.sub2=ghi,opt3=xyz",
|
||||
NULL, NULL, &error_abort);
|
||||
QDict *second = keyval_parse("opt1=ABC,opt2.sub2=GHI,opt2.sub3=JKL",
|
||||
NULL, NULL, &error_abort);
|
||||
QDict *combined = keyval_parse("opt1=ABC,opt2.sub1=def,opt2.sub2=GHI,opt2.sub3=JKL,opt3=xyz",
|
||||
NULL, NULL, &error_abort);
|
||||
Error *err = NULL;
|
||||
|
||||
keyval_merge(first, second, &err);
|
||||
g_assert(!err);
|
||||
g_assert(qobject_is_equal(QOBJECT(combined), QOBJECT(first)));
|
||||
qobject_unref(first);
|
||||
qobject_unref(second);
|
||||
qobject_unref(combined);
|
||||
}
|
||||
|
||||
static void test_keyval_merge_list(void)
|
||||
{
|
||||
QDict *first = keyval_parse("opt1.0=abc,opt2.0=xyz",
|
||||
NULL, NULL, &error_abort);
|
||||
QDict *second = keyval_parse("opt1.0=def",
|
||||
NULL, NULL, &error_abort);
|
||||
QDict *combined = keyval_parse("opt1.0=abc,opt1.1=def,opt2.0=xyz",
|
||||
NULL, NULL, &error_abort);
|
||||
Error *err = NULL;
|
||||
|
||||
keyval_merge(first, second, &err);
|
||||
g_assert(!err);
|
||||
g_assert(qobject_is_equal(QOBJECT(combined), QOBJECT(first)));
|
||||
qobject_unref(first);
|
||||
qobject_unref(second);
|
||||
qobject_unref(combined);
|
||||
}
|
||||
|
||||
static void test_keyval_merge_conflict(void)
|
||||
{
|
||||
QDict *first = keyval_parse("opt2=ABC",
|
||||
NULL, NULL, &error_abort);
|
||||
QDict *second = keyval_parse("opt2.sub1=def,opt2.sub2=ghi",
|
||||
NULL, NULL, &error_abort);
|
||||
QDict *third = qdict_clone_shallow(first);
|
||||
Error *err = NULL;
|
||||
|
||||
keyval_merge(first, second, &err);
|
||||
error_free_or_abort(&err);
|
||||
keyval_merge(second, third, &err);
|
||||
error_free_or_abort(&err);
|
||||
|
||||
qobject_unref(first);
|
||||
qobject_unref(second);
|
||||
qobject_unref(third);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
@ -760,6 +815,9 @@ int main(int argc, char *argv[])
|
|||
g_test_add_func("/keyval/visit/optional", test_keyval_visit_optional);
|
||||
g_test_add_func("/keyval/visit/alternate", test_keyval_visit_alternate);
|
||||
g_test_add_func("/keyval/visit/any", test_keyval_visit_any);
|
||||
g_test_add_func("/keyval/merge/dict", test_keyval_merge_dict);
|
||||
g_test_add_func("/keyval/merge/list", test_keyval_merge_list);
|
||||
g_test_add_func("/keyval/merge/conflict", test_keyval_merge_conflict);
|
||||
g_test_run();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -410,40 +410,6 @@ static void test_qemu_opts_reset(void)
|
|||
g_assert(opts == NULL);
|
||||
}
|
||||
|
||||
static void test_qemu_opts_set(void)
|
||||
{
|
||||
QemuOptsList *list;
|
||||
QemuOpts *opts;
|
||||
const char *opt;
|
||||
|
||||
list = qemu_find_opts("opts_list_04");
|
||||
g_assert(list != NULL);
|
||||
g_assert(QTAILQ_EMPTY(&list->head));
|
||||
g_assert_cmpstr(list->name, ==, "opts_list_04");
|
||||
|
||||
/* should not find anything at this point */
|
||||
opts = qemu_opts_find(list, NULL);
|
||||
g_assert(opts == NULL);
|
||||
|
||||
/* implicitly create opts and set str3 value */
|
||||
qemu_opts_set(list, "str3", "value", &error_abort);
|
||||
g_assert(!QTAILQ_EMPTY(&list->head));
|
||||
|
||||
/* get the just created opts */
|
||||
opts = qemu_opts_find(list, NULL);
|
||||
g_assert(opts != NULL);
|
||||
|
||||
/* check the str3 value */
|
||||
opt = qemu_opt_get(opts, "str3");
|
||||
g_assert_cmpstr(opt, ==, "value");
|
||||
|
||||
qemu_opts_del(opts);
|
||||
|
||||
/* should not find anything at this point */
|
||||
opts = qemu_opts_find(list, NULL);
|
||||
g_assert(opts == NULL);
|
||||
}
|
||||
|
||||
static int opts_count_iter(void *opaque, const char *name, const char *value,
|
||||
Error **errp)
|
||||
{
|
||||
|
@ -1041,7 +1007,6 @@ int main(int argc, char *argv[])
|
|||
g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size);
|
||||
g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
|
||||
g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
|
||||
g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set);
|
||||
g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse);
|
||||
g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
|
||||
g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
|
||||
|
|
123
util/keyval.c
123
util/keyval.c
|
@ -310,6 +310,86 @@ static char *reassemble_key(GSList *key)
|
|||
return g_string_free(s, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursive worker for keyval_merge.
|
||||
*
|
||||
* @str is the path that led to the * current dictionary (to be used for
|
||||
* error messages). It is modified internally but restored before the
|
||||
* function returns.
|
||||
*/
|
||||
static void keyval_do_merge(QDict *dest, const QDict *merged, GString *str, Error **errp)
|
||||
{
|
||||
size_t save_len = str->len;
|
||||
const QDictEntry *ent;
|
||||
QObject *old_value;
|
||||
|
||||
for (ent = qdict_first(merged); ent; ent = qdict_next(merged, ent)) {
|
||||
old_value = qdict_get(dest, ent->key);
|
||||
if (old_value) {
|
||||
if (qobject_type(old_value) != qobject_type(ent->value)) {
|
||||
error_setg(errp, "Parameter '%s%s' used inconsistently",
|
||||
str->str, ent->key);
|
||||
return;
|
||||
} else if (qobject_type(ent->value) == QTYPE_QDICT) {
|
||||
/* Merge sub-dictionaries. */
|
||||
g_string_append(str, ent->key);
|
||||
g_string_append_c(str, '.');
|
||||
keyval_do_merge(qobject_to(QDict, old_value),
|
||||
qobject_to(QDict, ent->value),
|
||||
str, errp);
|
||||
g_string_truncate(str, save_len);
|
||||
continue;
|
||||
} else if (qobject_type(ent->value) == QTYPE_QLIST) {
|
||||
/* Append to old list. */
|
||||
QList *old = qobject_to(QList, old_value);
|
||||
QList *new = qobject_to(QList, ent->value);
|
||||
const QListEntry *item;
|
||||
QLIST_FOREACH_ENTRY(new, item) {
|
||||
qobject_ref(item->value);
|
||||
qlist_append_obj(old, item->value);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
assert(qobject_type(ent->value) == QTYPE_QSTRING);
|
||||
}
|
||||
}
|
||||
|
||||
qobject_ref(ent->value);
|
||||
qdict_put_obj(dest, ent->key, ent->value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge the @merged dictionary into @dest.
|
||||
*
|
||||
* The dictionaries are expected to be returned by the keyval parser, and
|
||||
* therefore the only expected scalar type is the string. In case the same
|
||||
* path is present in both @dest and @merged, the semantics are as follows:
|
||||
*
|
||||
* - lists are concatenated
|
||||
*
|
||||
* - dictionaries are merged recursively
|
||||
*
|
||||
* - for scalar values, @merged wins
|
||||
*
|
||||
* In case an error is reported, @dest may already have been modified.
|
||||
*
|
||||
* This function can be used to implement semantics analogous to QemuOpts's
|
||||
* .merge_lists = true case, or to implement -set for options backed by QDicts.
|
||||
*
|
||||
* Note: while QemuOpts is commonly used so that repeated keys overwrite
|
||||
* ("last one wins"), it can also be used so that repeated keys build up
|
||||
* a list. keyval_merge() can only be used when the options' semantics are
|
||||
* the former, not the latter.
|
||||
*/
|
||||
void keyval_merge(QDict *dest, const QDict *merged, Error **errp)
|
||||
{
|
||||
GString *str;
|
||||
|
||||
str = g_string_new("");
|
||||
keyval_do_merge(dest, merged, str, errp);
|
||||
g_string_free(str, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Listify @cur recursively.
|
||||
* Replace QDicts whose keys are all valid list indexes by QLists.
|
||||
|
@ -431,13 +511,14 @@ static QObject *keyval_listify(QDict *cur, GSList *key_of_cur, Error **errp)
|
|||
* If @p_help is not NULL, store whether help is requested there.
|
||||
* If @p_help is NULL and help is requested, fail.
|
||||
*
|
||||
* On success, return a dictionary of the parsed keys and values.
|
||||
* On failure, store an error through @errp and return NULL.
|
||||
* On success, return @dict, now filled with the parsed keys and values.
|
||||
*
|
||||
* On failure, store an error through @errp and return NULL. Any keys
|
||||
* and values parsed so far will be in @dict nevertheless.
|
||||
*/
|
||||
QDict *keyval_parse(const char *params, const char *implied_key,
|
||||
bool *p_help, Error **errp)
|
||||
QDict *keyval_parse_into(QDict *qdict, const char *params, const char *implied_key,
|
||||
bool *p_help, Error **errp)
|
||||
{
|
||||
QDict *qdict = qdict_new();
|
||||
QObject *listified;
|
||||
const char *s;
|
||||
bool help = false;
|
||||
|
@ -446,7 +527,6 @@ QDict *keyval_parse(const char *params, const char *implied_key,
|
|||
while (*s) {
|
||||
s = keyval_parse_one(qdict, s, implied_key, &help, errp);
|
||||
if (!s) {
|
||||
qobject_unref(qdict);
|
||||
return NULL;
|
||||
}
|
||||
implied_key = NULL;
|
||||
|
@ -456,15 +536,42 @@ QDict *keyval_parse(const char *params, const char *implied_key,
|
|||
*p_help = help;
|
||||
} else if (help) {
|
||||
error_setg(errp, "Help is not available for this option");
|
||||
qobject_unref(qdict);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
listified = keyval_listify(qdict, NULL, errp);
|
||||
if (!listified) {
|
||||
qobject_unref(qdict);
|
||||
return NULL;
|
||||
}
|
||||
assert(listified == QOBJECT(qdict));
|
||||
return qdict;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse @params in QEMU's traditional KEY=VALUE,... syntax.
|
||||
*
|
||||
* If @implied_key, the first KEY= can be omitted. @implied_key is
|
||||
* implied then, and VALUE can't be empty or contain ',' or '='.
|
||||
*
|
||||
* A parameter "help" or "?" without a value isn't added to the
|
||||
* resulting dictionary, but instead is interpreted as help request.
|
||||
* All other options are parsed and returned normally so that context
|
||||
* specific help can be printed.
|
||||
*
|
||||
* If @p_help is not NULL, store whether help is requested there.
|
||||
* If @p_help is NULL and help is requested, fail.
|
||||
*
|
||||
* On success, return a dictionary of the parsed keys and values.
|
||||
* On failure, store an error through @errp and return NULL.
|
||||
*/
|
||||
QDict *keyval_parse(const char *params, const char *implied_key,
|
||||
bool *p_help, Error **errp)
|
||||
{
|
||||
QDict *qdict = qdict_new();
|
||||
QDict *ret = keyval_parse_into(qdict, params, implied_key, p_help, errp);
|
||||
|
||||
if (!ret) {
|
||||
qobject_unref(qdict);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
util_ss.add(dependency('threads'))
|
||||
util_ss.add(files('osdep.c', 'cutils.c', 'unicode.c', 'qemu-timer-common.c'))
|
||||
util_ss.add(when: 'CONFIG_ATOMIC64', if_false: files('atomic64.c'))
|
||||
util_ss.add(when: 'CONFIG_POSIX', if_true: files('aio-posix.c'))
|
||||
util_ss.add(when: 'CONFIG_POSIX', if_true: files('fdmon-poll.c'))
|
||||
util_ss.add(when: 'CONFIG_EPOLL_CREATE1', if_true: files('fdmon-epoll.c'))
|
||||
if config_host_data.get('CONFIG_EPOLL_CREATE1')
|
||||
util_ss.add(files('fdmon-epoll.c'))
|
||||
endif
|
||||
util_ss.add(when: ['CONFIG_LINUX_IO_URING', linux_io_uring], if_true: files('fdmon-io_uring.c'))
|
||||
util_ss.add(when: 'CONFIG_POSIX', if_true: files('compatfd.c'))
|
||||
util_ss.add(when: 'CONFIG_POSIX', if_true: files('event_notifier-posix.c'))
|
||||
|
|
|
@ -479,19 +479,14 @@ int qemu_opt_unset(QemuOpts *opts, const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value,
|
||||
bool prepend)
|
||||
static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value)
|
||||
{
|
||||
QemuOpt *opt = g_malloc0(sizeof(*opt));
|
||||
|
||||
opt->name = g_strdup(name);
|
||||
opt->str = value;
|
||||
opt->opts = opts;
|
||||
if (prepend) {
|
||||
QTAILQ_INSERT_HEAD(&opts->head, opt, next);
|
||||
} else {
|
||||
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
|
||||
|
||||
return opt;
|
||||
}
|
||||
|
@ -518,7 +513,7 @@ static bool opt_validate(QemuOpt *opt, Error **errp)
|
|||
bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
|
||||
Error **errp)
|
||||
{
|
||||
QemuOpt *opt = opt_create(opts, name, g_strdup(value), false);
|
||||
QemuOpt *opt = opt_create(opts, name, g_strdup(value));
|
||||
|
||||
if (!opt_validate(opt, errp)) {
|
||||
qemu_opt_del(opt);
|
||||
|
@ -662,15 +657,6 @@ void qemu_opts_loc_restore(QemuOpts *opts)
|
|||
loc_restore(&opts->loc);
|
||||
}
|
||||
|
||||
bool qemu_opts_set(QemuOptsList *list, const char *name, const char *value, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
|
||||
assert(list->merge_lists);
|
||||
opts = qemu_opts_create(list, NULL, 0, &error_abort);
|
||||
return qemu_opt_set(opts, name, value, errp);
|
||||
}
|
||||
|
||||
const char *qemu_opts_id(QemuOpts *opts)
|
||||
{
|
||||
return opts->id;
|
||||
|
@ -811,7 +797,7 @@ static const char *get_opt_name_value(const char *params,
|
|||
}
|
||||
|
||||
static bool opts_do_parse(QemuOpts *opts, const char *params,
|
||||
const char *firstname, bool prepend,
|
||||
const char *firstname,
|
||||
bool warn_on_flag, bool *help_wanted, Error **errp)
|
||||
{
|
||||
char *option, *value;
|
||||
|
@ -833,7 +819,7 @@ static bool opts_do_parse(QemuOpts *opts, const char *params,
|
|||
continue;
|
||||
}
|
||||
|
||||
opt = opt_create(opts, option, value, prepend);
|
||||
opt = opt_create(opts, option, value);
|
||||
g_free(option);
|
||||
if (!opt_validate(opt, errp)) {
|
||||
qemu_opt_del(opt);
|
||||
|
@ -889,11 +875,11 @@ bool has_help_option(const char *params)
|
|||
bool qemu_opts_do_parse(QemuOpts *opts, const char *params,
|
||||
const char *firstname, Error **errp)
|
||||
{
|
||||
return opts_do_parse(opts, params, firstname, false, false, NULL, errp);
|
||||
return opts_do_parse(opts, params, firstname, false, NULL, errp);
|
||||
}
|
||||
|
||||
static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
|
||||
bool permit_abbrev, bool defaults,
|
||||
bool permit_abbrev,
|
||||
bool warn_on_flag, bool *help_wanted, Error **errp)
|
||||
{
|
||||
const char *firstname;
|
||||
|
@ -903,21 +889,13 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
|
|||
assert(!permit_abbrev || list->implied_opt_name);
|
||||
firstname = permit_abbrev ? list->implied_opt_name : NULL;
|
||||
|
||||
/*
|
||||
* This code doesn't work for defaults && !list->merge_lists: when
|
||||
* params has no id=, and list has an element with !opts->id, it
|
||||
* appends a new element instead of returning the existing opts.
|
||||
* However, we got no use for this case. Guard against possible
|
||||
* (if unlikely) future misuse:
|
||||
*/
|
||||
assert(!defaults || list->merge_lists);
|
||||
opts = qemu_opts_create(list, id, !list->merge_lists, errp);
|
||||
g_free(id);
|
||||
if (opts == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!opts_do_parse(opts, params, firstname, defaults,
|
||||
if (!opts_do_parse(opts, params, firstname,
|
||||
warn_on_flag, help_wanted, errp)) {
|
||||
qemu_opts_del(opts);
|
||||
return NULL;
|
||||
|
@ -936,7 +914,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
|
|||
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
|
||||
bool permit_abbrev, Error **errp)
|
||||
{
|
||||
return opts_parse(list, params, permit_abbrev, false, false, NULL, errp);
|
||||
return opts_parse(list, params, permit_abbrev, false, NULL, errp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -954,7 +932,7 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
|
|||
QemuOpts *opts;
|
||||
bool help_wanted = false;
|
||||
|
||||
opts = opts_parse(list, params, permit_abbrev, false, true,
|
||||
opts = opts_parse(list, params, permit_abbrev, true,
|
||||
opts_accepts_any(list) ? NULL : &help_wanted,
|
||||
&err);
|
||||
if (!opts) {
|
||||
|
@ -968,15 +946,6 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
|
|||
return opts;
|
||||
}
|
||||
|
||||
void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
|
||||
int permit_abbrev)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
|
||||
opts = opts_parse(list, params, permit_abbrev, true, false, NULL, NULL);
|
||||
assert(opts);
|
||||
}
|
||||
|
||||
static bool qemu_opts_from_qdict_entry(QemuOpts *opts,
|
||||
const QDictEntry *entry,
|
||||
Error **errp)
|
||||
|
|
Loading…
Reference in New Issue