* 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:
Peter Maydell 2021-07-06 11:24:58 +01:00
commit 9aef095419
34 changed files with 1179 additions and 1588 deletions

View File

@ -14,7 +14,7 @@ SRC_PATH=.
# we have explicit rules for everything # we have explicit rules for everything
MAKEFLAGS += -rR MAKEFLAGS += -rR
SHELL = /usr/bin/env bash -o pipefail SHELL = bash -o pipefail
# Usage: $(call quiet-command,command and args,"NAME","args to print") # Usage: $(call quiet-command,command and args,"NAME","args to print")
# This will run "command and args", and either: # This will run "command and args", and either:

1023
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -303,5 +303,5 @@ variable::
host_kconfig = \ host_kconfig = \
('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \ ('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \
('CONFIG_SPICE' in config_host ? ['CONFIG_SPICE=y'] : []) + \ ('CONFIG_SPICE' in config_host ? ['CONFIG_SPICE=y'] : []) + \
('CONFIG_IVSHMEM' in config_host ? ['CONFIG_IVSHMEM=y'] : []) + \ (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \
... ...

View File

@ -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 if they were not given. The property is therefore useless and should not be
specified. 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 QEMU Machine Protocol (QMP) commands
------------------------------------ ------------------------------------

View File

@ -19,6 +19,7 @@
#include "hw/loader.h" #include "hw/loader.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-common.h"
#include "qapi/qapi-visit-machine.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
@ -799,6 +800,57 @@ static void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
ms->smp.sockets = sockets; 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) static void machine_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); 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", object_class_property_set_description(oc, "dumpdtb",
"Dump current dtb to a file and quit"); "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", object_class_property_add(oc, "phandle-start", "int",
machine_get_phandle_start, machine_set_phandle_start, machine_get_phandle_start, machine_set_phandle_start,
NULL, NULL); NULL, NULL);
@ -1126,56 +1184,6 @@ MemoryRegion *machine_consume_memdev(MachineState *machine,
return ret; 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) void machine_run_board_init(MachineState *machine)
{ {
MachineClass *machine_class = MACHINE_GET_CLASS(machine); MachineClass *machine_class = MACHINE_GET_CLASS(machine);

View File

@ -61,7 +61,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
hw_display_modules += {'virtio-gpu': virtio_gpu_ss} hw_display_modules += {'virtio-gpu': virtio_gpu_ss}
virtio_gpu_gl_ss = ss.source_set() 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]) if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl])
hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss} hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss}
endif endif
@ -75,7 +75,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss} hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss}
virtio_gpu_pci_gl_ss = ss.source_set() 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]) if_true: [files('virtio-gpu-pci-gl.c'), pixman])
hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss} hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss}
endif endif
@ -89,7 +89,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
hw_display_modules += {'virtio-vga': virtio_vga_ss} hw_display_modules += {'virtio-vga': virtio_vga_ss}
virtio_vga_gl_ss = ss.source_set() 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]) if_true: [files('virtio-vga-gl.c'), pixman])
hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss} hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss}
endif endif

View File

@ -26,7 +26,6 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE)
extern MachineState *current_machine; extern MachineState *current_machine;
void machine_run_board_init(MachineState *machine); void machine_run_board_init(MachineState *machine);
bool machine_smp_parse(MachineState *ms, QemuOpts *opts, Error **errp);
bool machine_usb(MachineState *machine); bool machine_usb(MachineState *machine);
int machine_phandle_start(MachineState *machine); int machine_phandle_start(MachineState *machine);
bool machine_dump_guest_core(MachineState *machine); bool machine_dump_guest_core(MachineState *machine);

View File

@ -119,7 +119,6 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
int fail_if_exists, Error **errp); int fail_if_exists, Error **errp);
void qemu_opts_reset(QemuOptsList *list); void qemu_opts_reset(QemuOptsList *list);
void qemu_opts_loc_restore(QemuOpts *opts); 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); const char *qemu_opts_id(QemuOpts *opts);
void qemu_opts_set_id(QemuOpts *opts, char *id); void qemu_opts_set_id(QemuOpts *opts, char *id);
void qemu_opts_del(QemuOpts *opts); void qemu_opts_del(QemuOpts *opts);
@ -130,8 +129,6 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
bool permit_abbrev); bool permit_abbrev);
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
bool permit_abbrev, Error **errp); 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, QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
Error **errp); Error **errp);
QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict, 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); void qemu_opts_free(QemuOptsList *list);
QemuOptsList *qemu_opts_append(QemuOptsList *dst, 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, QDict *keyval_parse(const char *params, const char *implied_key,
bool *help, Error **errp); bool *help, Error **errp);
void keyval_merge(QDict *old, const QDict *new, Error **errp);
#endif #endif

View File

@ -861,6 +861,29 @@ static void do_qemu_init_ ## type_array(void) \
} \ } \
type_init(do_qemu_init_ ## type_array) 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: * object_class_dynamic_cast_assert:
* @klass: The #ObjectClass to attempt to cast. * @klass: The #ObjectClass to attempt to cast.

View File

@ -164,6 +164,7 @@ endif
multiprocess_allowed = targetos == 'linux' and not get_option('multiprocess').disabled() multiprocess_allowed = targetos == 'linux' and not get_option('multiprocess').disabled()
libm = cc.find_library('m', required: false) libm = cc.find_library('m', required: false)
threads = dependency('threads')
util = cc.find_library('util', required: false) util = cc.find_library('util', required: false)
winmm = [] winmm = []
socket = [] socket = []
@ -327,15 +328,16 @@ if have_system or have_tools
endif endif
libaio = cc.find_library('aio', required: false) libaio = cc.find_library('aio', required: false)
zlib = dependency('zlib', required: true, kwargs: static_kwargs) zlib = dependency('zlib', required: true, kwargs: static_kwargs)
linux_io_uring = not_found linux_io_uring = not_found
if 'CONFIG_LINUX_IO_URING' in config_host if not get_option('linux_io_uring').auto() or have_block
linux_io_uring = declare_dependency(compile_args: config_host['LINUX_IO_URING_CFLAGS'].split(), linux_io_uring = dependency('liburing', required: get_option('linux_io_uring'),
link_args: config_host['LINUX_IO_URING_LIBS'].split()) method: 'pkg-config', kwargs: static_kwargs)
endif endif
libxml2 = not_found libxml2 = not_found
if 'CONFIG_LIBXML2' in config_host if not get_option('libxml2').auto() or have_block
libxml2 = declare_dependency(compile_args: config_host['LIBXML2_CFLAGS'].split(), libxml2 = dependency('libxml-2.0', required: get_option('libxml2'),
link_args: config_host['LIBXML2_LIBS'].split()) method: 'pkg-config', kwargs: static_kwargs)
endif endif
libnfs = not_found libnfs = not_found
if not get_option('libnfs').auto() or have_block 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()) link_args: config_host['GBM_LIBS'].split())
endif endif
virgl = not_found virgl = not_found
if 'CONFIG_VIRGL' in config_host if not get_option('virglrenderer').auto() or have_system
virgl = declare_dependency(compile_args: config_host['VIRGL_CFLAGS'].split(), virgl = dependency('virglrenderer',
link_args: config_host['VIRGL_LIBS'].split()) method: 'pkg-config',
required: get_option('virglrenderer'),
kwargs: static_kwargs)
endif endif
curl = not_found curl = not_found
if not get_option('curl').auto() or have_block if not get_option('curl').auto() or have_block
@ -860,6 +864,7 @@ endif
gtk = not_found gtk = not_found
gtkx11 = not_found gtkx11 = not_found
vte = not_found
if not get_option('gtk').auto() or (have_system and not cocoa.found()) if not get_option('gtk').auto() or (have_system and not cocoa.found())
gtk = dependency('gtk+-3.0', version: '>=3.22.0', gtk = dependency('gtk+-3.0', version: '>=3.22.0',
method: 'pkg-config', method: 'pkg-config',
@ -871,14 +876,16 @@ if not get_option('gtk').auto() or (have_system and not cocoa.found())
required: false, required: false,
kwargs: static_kwargs) kwargs: static_kwargs)
gtk = declare_dependency(dependencies: [gtk, gtkx11]) 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
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 x11 = not_found
if gtkx11.found() if gtkx11.found()
x11 = dependency('x11', method: 'pkg-config', required: 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 endif
libpmem = not_found libpmem = not_found
if 'CONFIG_LIBPMEM' in config_host if not get_option('libpmem').auto() or have_system
libpmem = declare_dependency(compile_args: config_host['LIBPMEM_CFLAGS'].split(), libpmem = dependency('libpmem', required: get_option('libpmem'),
link_args: config_host['LIBPMEM_LIBS'].split()) method: 'pkg-config', kwargs: static_kwargs)
endif endif
libdaxctl = not_found libdaxctl = not_found
if 'CONFIG_LIBDAXCTL' in config_host if not get_option('libdaxctl').auto() or have_system
libdaxctl = declare_dependency(link_args: config_host['LIBDAXCTL_LIBS'].split()) libdaxctl = dependency('libdaxctl', required: get_option('libdaxctl'),
version: '>=57', method: 'pkg-config',
kwargs: static_kwargs)
endif endif
tasn1 = not_found tasn1 = not_found
if gnutls.found() if gnutls.found()
@ -1042,10 +1051,12 @@ endif
# Check whether the glibc provides statx() # Check whether the glibc provides statx()
statx_test = ''' gnu_source_prefix = '''
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
'''
statx_test = gnu_source_prefix + '''
#include <sys/stat.h> #include <sys/stat.h>
int main(void) { int main(void) {
struct statx statxbuf; struct statx statxbuf;
@ -1208,6 +1219,7 @@ if glusterfs.found()
config_host_data.set('CONFIG_GLUSTERFS_IOCB_HAS_STAT', glusterfs_iocb_has_stat) config_host_data.set('CONFIG_GLUSTERFS_IOCB_HAS_STAT', glusterfs_iocb_has_stat)
endif endif
config_host_data.set('CONFIG_GTK', gtk.found()) 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_LIBATTR', have_old_libattr)
config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found()) config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
config_host_data.set('CONFIG_EBPF', libbpf.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_MINOR', meson.project_version().split('.')[1])
config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2]) 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_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_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_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_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_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_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 ignored = ['CONFIG_QEMU_INTERP_PREFIX'] # actually per-target
arrays = ['CONFIG_AUDIO_DRIVERS', 'CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST'] arrays = ['CONFIG_AUDIO_DRIVERS', 'CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST']
@ -1322,10 +1468,11 @@ if link_language == 'cpp'
} }
endif endif
have_ivshmem = config_host_data.get('CONFIG_EVENTFD')
host_kconfig = \ host_kconfig = \
('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \ ('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \
('CONFIG_SPICE' in config_host ? ['CONFIG_SPICE=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'] : []) + \ ('CONFIG_OPENGL' in config_host ? ['CONFIG_OPENGL=y'] : []) + \
(x11.found() ? ['CONFIG_X11=y'] : []) + \ (x11.found() ? ['CONFIG_X11=y'] : []) + \
('CONFIG_VHOST_USER' in config_host ? ['CONFIG_VHOST_USER=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) util_ss = util_ss.apply(config_all, strict: false)
libqemuutil = static_library('qemuutil', libqemuutil = static_library('qemuutil',
sources: util_ss.sources() + stub_ss.sources() + genh, 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, qemuutil = declare_dependency(link_with: libqemuutil,
sources: genh + version_res) sources: genh + version_res)
@ -2360,8 +2507,7 @@ foreach target : target_dirs
endif endif
foreach exe: execs foreach exe: execs
exe_name = exe['name'] exe_name = exe['name']
exe_sign = 'CONFIG_HVF' in config_target if targetos == 'darwin'
if exe_sign
exe_name += '-unsigned' exe_name += '-unsigned'
endif endif
@ -2375,7 +2521,13 @@ foreach target : target_dirs
link_args: link_args, link_args: link_args,
gui_app: exe['gui']) 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'], emulators += {exe['name'] : custom_target(exe['name'],
depends: emulator, depends: emulator,
output: exe['name'], output: exe['name'],
@ -2383,14 +2535,14 @@ foreach target : target_dirs
meson.current_source_dir() / 'scripts/entitlement.sh', meson.current_source_dir() / 'scripts/entitlement.sh',
meson.current_build_dir() / exe_name, meson.current_build_dir() / exe_name,
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', meson.add_install_script('scripts/entitlement.sh', '--install',
get_option('bindir') / exe_name, get_option('bindir') / exe_name,
get_option('bindir') / exe['name'], get_option('bindir') / exe['name'],
meson.current_source_dir() / 'accel/hvf/entitlements.plist') entitlements, icon)
else else
emulators += {exe['name']: emulator} emulators += {exe['name']: emulator}
endif endif
@ -2476,7 +2628,7 @@ if have_tools
install: true) install: true)
endif endif
if 'CONFIG_IVSHMEM' in config_host if have_ivshmem
subdir('contrib/ivshmem-client') subdir('contrib/ivshmem-client')
subdir('contrib/ivshmem-server') subdir('contrib/ivshmem-server')
endif endif
@ -2613,7 +2765,6 @@ if targetos == 'windows'
summary_info += {'Windows SDK': config_host['WIN_SDK']} summary_info += {'Windows SDK': config_host['WIN_SDK']}
endif endif
endif endif
summary_info += {'ARFLAGS': config_host['ARFLAGS']}
summary_info += {'CFLAGS': ' '.join(get_option('c_args') summary_info += {'CFLAGS': ' '.join(get_option('c_args')
+ ['-O' + get_option('optimization')] + ['-O' + get_option('optimization')]
+ (get_option('debug') ? ['-g'] : []))} + (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 += {'static build': config_host.has_key('CONFIG_STATIC')}
summary_info += {'malloc trim support': has_malloc_trim} summary_info += {'malloc trim support': has_malloc_trim}
summary_info += {'membarrier': config_host.has_key('CONFIG_MEMBARRIER')} 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 += {'debug stack usage': config_host.has_key('CONFIG_DEBUG_STACK_USAGE')}
summary_info += {'mutex debugging': config_host.has_key('CONFIG_DEBUG_MUTEX')} summary_info += {'mutex debugging': config_host.has_key('CONFIG_DEBUG_MUTEX')}
summary_info += {'memory allocator': get_option('malloc')} 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 += {'GTK support': gtk.found()}
summary_info += {'pixman': pixman.found()} summary_info += {'pixman': pixman.found()}
# TODO: add back version # TODO: add back version
summary_info += {'VTE support': config_host.has_key('CONFIG_VTE')} summary_info += {'VTE support': vte.found()}
# TODO: add back version # TODO: add back version
summary_info += {'slirp support': slirp_opt == 'disabled' ? false : slirp_opt} summary_info += {'slirp support': slirp_opt == 'disabled' ? false : slirp_opt}
summary_info += {'libtasn1': tasn1.found()} summary_info += {'libtasn1': tasn1.found()}
@ -2764,7 +2911,7 @@ summary_info += {'PAM': pam.found()}
summary_info += {'iconv support': iconv.found()} summary_info += {'iconv support': iconv.found()}
summary_info += {'curses support': curses.found()} summary_info += {'curses support': curses.found()}
# TODO: add back version # 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 += {'curl support': curl.found()}
summary_info += {'Multipath support': mpathpersist.found()} summary_info += {'Multipath support': mpathpersist.found()}
summary_info += {'VNC support': vnc.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 += {'vde support': config_host.has_key('CONFIG_VDE')}
summary_info += {'netmap support': config_host.has_key('CONFIG_NETMAP')} 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 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 += {'ATTR/XATTR support': libattr.found()}
summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')} summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')}
summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')} 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 += {'lzfse support': liblzfse.found()}
summary_info += {'zstd support': zstd.found()} summary_info += {'zstd support': zstd.found()}
summary_info += {'NUMA host support': config_host.has_key('CONFIG_NUMA')} 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 += {'capstone': capstone_opt == 'disabled' ? false : capstone_opt}
summary_info += {'libpmem support': config_host.has_key('CONFIG_LIBPMEM')} summary_info += {'libpmem support': libpmem.found()}
summary_info += {'libdaxctl support': config_host.has_key('CONFIG_LIBDAXCTL')} summary_info += {'libdaxctl support': libdaxctl.found()}
summary_info += {'libudev': libudev.found()} summary_info += {'libudev': libudev.found()}
summary_info += {'FUSE lseek': fuse_lseek.found()} summary_info += {'FUSE lseek': fuse_lseek.found()}
summary(summary_info, bool_yn: true, section: 'Dependencies') summary(summary_info, bool_yn: true, section: 'Dependencies')

View File

@ -84,10 +84,18 @@ option('nettle', type : 'feature', value : 'auto',
description: 'nettle cryptography support') description: 'nettle cryptography support')
option('gcrypt', type : 'feature', value : 'auto', option('gcrypt', type : 'feature', value : 'auto',
description: 'libgcrypt cryptography support') 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', option('libudev', type : 'feature', value : 'auto',
description: 'Use libudev to enumerate host devices') description: 'Use libudev to enumerate host devices')
option('libusb', type : 'feature', value : 'auto', option('libusb', type : 'feature', value : 'auto',
description: 'libusb support for USB passthrough') 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', option('lzfse', type : 'feature', value : 'auto',
description: 'lzfse support for DMG images') description: 'lzfse support for DMG images')
option('lzo', type : 'feature', value : 'auto', option('lzo', type : 'feature', value : 'auto',
@ -110,6 +118,8 @@ option('u2f', type : 'feature', value : 'auto',
description: 'U2F emulation support') description: 'U2F emulation support')
option('usb_redir', type : 'feature', value : 'auto', option('usb_redir', type : 'feature', value : 'auto',
description: 'libusbredir support') description: 'libusbredir support')
option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
option('vnc', type : 'feature', value : 'enabled', option('vnc', type : 'feature', value : 'enabled',
description: 'VNC server') description: 'VNC server')
option('vnc_jpeg', type : 'feature', value : 'auto', option('vnc_jpeg', type : 'feature', value : 'auto',
@ -118,6 +128,8 @@ option('vnc_png', type : 'feature', value : 'auto',
description: 'PNG compression for VNC server') description: 'PNG compression for VNC server')
option('vnc_sasl', type : 'feature', value : 'auto', option('vnc_sasl', type : 'feature', value : 'auto',
description: 'SASL authentication for VNC server') 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', option('xkbcommon', type : 'feature', value : 'auto',
description: 'xkbcommon support') description: 'xkbcommon support')
option('zstd', type : 'feature', value : 'auto', option('zstd', type : 'feature', value : 'auto',

View File

@ -1783,11 +1783,12 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
"-display spice-app[,gl=on|off]\n" "-display spice-app[,gl=on|off]\n"
#endif #endif
#if defined(CONFIG_SDL) #if defined(CONFIG_SDL)
"-display sdl[,alt_grab=on|off][,ctrl_grab=on|off]\n" "-display sdl[,alt_grab=on|off][,ctrl_grab=on|off][,gl=on|core|es|off]\n"
" [,window_close=on|off][,gl=on|core|es|off]\n" " [,show-cursor=on|off][,window-close=on|off]\n"
#endif #endif
#if defined(CONFIG_GTK) #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 #endif
#if defined(CONFIG_VNC) #if defined(CONFIG_VNC)
"-display vnc=<display>[,<optargs>]\n" "-display vnc=<display>[,<optargs>]\n"
@ -1824,17 +1825,37 @@ SRST
application. The Spice server will redirect the serial consoles application. The Spice server will redirect the serial consoles
and QEMU monitors. (Since 4.0) 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 Display video output via SDL (usually in a separate graphics
window; see the SDL documentation for other possibilities). 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 Display video output in a GTK window. This interface provides
drop-down menus and other UI elements to configure and control 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 Display video output via curses. For graphics device models
which support a text mode, QEMU can display this output using a which support a text mode, QEMU can display this output using a
curses/ncurses interface. Nothing is displayed when the graphics curses/ncurses interface. Nothing is displayed when the graphics
@ -1845,11 +1866,14 @@ SRST
``charset=CP850`` for IBM CP850 encoding. The default is ``charset=CP850`` for IBM CP850 encoding. The default is
``CP437``. ``CP437``.
``egl-headless[,rendernode<file>]`` ``egl-headless[,rendernode=<file>]``
Offload all OpenGL operations to a local DRI device. For any Offload all OpenGL operations to a local DRI device. For any
graphical display, this display needs to be paired with either graphical display, this display needs to be paired with either
VNC or SPICE displays. VNC or SPICE displays.
``vnc=<display>``
Start a VNC server on display <display>
``none`` ``none``
Do not display video output. The guest will still see an Do not display video output. The guest will still see an
emulated graphics card, but its output will not be displayed to 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 that it only affects what is done with video output; -nographic
also changes the destination of the serial and parallel port also changes the destination of the serial and parallel port
data. data.
ERST ERST
DEF("nographic", 0, QEMU_OPTION_nographic, DEF("nographic", 0, QEMU_OPTION_nographic,
@ -1910,10 +1931,11 @@ SRST
ERST ERST
DEF("no-quit", 0, QEMU_OPTION_no_quit, 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 SRST
``-no-quit`` ``-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 ERST
DEF("sdl", 0, QEMU_OPTION_sdl, DEF("sdl", 0, QEMU_OPTION_sdl,

View File

@ -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, Object *user_creatable_add_type(const char *type, const char *id,
const QDict *qdict, const QDict *qdict,
Visitor *v, Error **errp) Visitor *v, Error **errp)
@ -49,7 +87,6 @@ Object *user_creatable_add_type(const char *type, const char *id,
ERRP_GUARD(); ERRP_GUARD();
Object *obj; Object *obj;
ObjectClass *klass; ObjectClass *klass;
const QDictEntry *e;
Error *local_err = NULL; Error *local_err = NULL;
if (id != NULL && !id_wellformed(id)) { if (id != NULL && !id_wellformed(id)) {
@ -78,18 +115,7 @@ Object *user_creatable_add_type(const char *type, const char *id,
assert(qdict); assert(qdict);
obj = object_new(type); obj = object_new(type);
if (!visit_start_struct(v, NULL, NULL, 0, &local_err)) { object_set_properties_from_qdict(obj, qdict, v, &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);
if (local_err) { if (local_err) {
goto out; goto out;
} }
@ -178,7 +204,7 @@ static void user_creatable_print_types(void)
g_slist_free(list); g_slist_free(list);
} }
static bool user_creatable_print_type_properites(const char *type) bool type_print_class_properties(const char *type)
{ {
ObjectClass *klass; ObjectClass *klass;
ObjectPropertyIterator iter; ObjectPropertyIterator iter;
@ -224,7 +250,7 @@ bool user_creatable_print_help(const char *type, QemuOpts *opts)
} }
if (qemu_opt_has_help_opt(opts)) { if (qemu_opt_has_help_opt(opts)) {
return user_creatable_print_type_properites(type); return type_print_class_properties(type);
} }
return false; 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"); 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(); user_creatable_print_types();
} }
} }

View File

@ -21,9 +21,6 @@ hppa
i386 i386
~ (/qemu)?((/include)?/hw/i386/.*|/target/i386/.*|/hw/intc/[^/]*apic[^/]*\.c) ~ (/qemu)?((/include)?/hw/i386/.*|/target/i386/.*|/hw/intc/[^/]*apic[^/]*\.c)
lm32
~ (/qemu)?((/include)?/hw/lm32/.*|/target/lm32/.*|/hw/.*/(milkymist|lm32).*)
m68k m68k
~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*) ~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*)
@ -60,9 +57,6 @@ tilegx
tricore tricore
~ (/qemu)?((/include)?/hw/tricore/.*|/target/tricore/.*) ~ (/qemu)?((/include)?/hw/tricore/.*|/target/tricore/.*)
unicore32
~ (/qemu)?((/include)?/hw/unicore32/.*|/target/unicore32/.*)
9pfs 9pfs
~ (/qemu)?(/hw/9pfs/.*|/fsdev/.*) ~ (/qemu)?(/hw/9pfs/.*|/fsdev/.*)

View File

@ -380,15 +380,17 @@ export PATH="$TOOLBIN:$PATH"
cd "$SRCDIR" cd "$SRCDIR"
echo "Doing make distclean..." echo "Nuking build directory..."
make distclean rm -rf +build
mkdir +build
cd +build
echo "Configuring..." echo "Configuring..."
# We configure with a fixed set of enables here to ensure that we don't # 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 # 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 system that's missing a dependency that we need to build part of
# the codebase. # the codebase.
./configure --disable-modules --enable-sdl --enable-gtk \ ../configure --disable-modules --enable-sdl --enable-gtk \
--enable-opengl --enable-vte --enable-gnutls \ --enable-opengl --enable-vte --enable-gnutls \
--enable-nettle --enable-curses --enable-curl \ --enable-nettle --enable-curses --enable-curl \
--audio-drv-list=oss,alsa,sdl,pa --enable-virtfs \ --audio-drv-list=oss,alsa,sdl,pa --enable-virtfs \

View File

@ -11,6 +11,7 @@ fi
SRC="$1" SRC="$1"
DST="$2" DST="$2"
ENTITLEMENT="$3" ENTITLEMENT="$3"
ICON="$4"
if $in_place; then if $in_place; then
trap 'rm "$DST.tmp"' exit trap 'rm "$DST.tmp"' exit
@ -20,6 +21,13 @@ else
cd "$MESON_INSTALL_DESTDIR_PREFIX" cd "$MESON_INSTALL_DESTDIR_PREFIX"
fi 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" mv -f "$SRC" "$DST"
trap '' exit trap '' exit

View File

@ -145,6 +145,8 @@ static const char *cpu_option;
static const char *mem_path; static const char *mem_path;
static const char *incoming; static const char *incoming;
static const char *loadvm; 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 QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts);
static ram_addr_t maxram_size; static ram_addr_t maxram_size;
static uint64_t ram_slots; 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 = { static QemuOptsList qemu_accel_opts = {
.name = "accel", .name = "accel",
.implied_opt_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) const char *qemu_get_vm_name(void)
{ {
return qemu_name; return qemu_name;
@ -815,33 +792,6 @@ static MachineClass *find_default_machine(GSList *machines)
return default_machineclass; 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) static void version(void)
{ {
printf("QEMU emulator version " QEMU_FULL_VERSION "\n" 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 * sdl DisplayType needs hand-crafted parser instead of
* parse_display_qapi() due to some options not in * parse_display_qapi() due to some options not in
* DisplayOptions, specifically: * DisplayOptions, specifically:
* - frame
* Already deprecated.
* - ctrl_grab + alt_grab * - ctrl_grab + alt_grab
* Not clear yet what happens to them long-term. Should * Not clear yet what happens to them long-term. Should
* replaced by something better or deprecated and dropped. * replaced by something better or deprecated and dropped.
@ -1091,7 +1039,12 @@ static void parse_display(const char *p)
} else { } else {
goto invalid_sdl_args; 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; opts = nextopt;
dpy.has_window_close = true; dpy.has_window_close = true;
if (strstart(opts, "on", &nextopt)) { 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))); 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 *machines, *el;
GSList *el; const char *type = qdict_get_try_str(qdict, "type");
if (is_help_option(name)) { machines = object_class_get_list(TYPE_MACHINE, false);
printf("Supported machines are:\n"); if (type) {
machines = g_slist_sort(machines, machine_class_cmp); ObjectClass *machine_class = OBJECT_CLASS(find_machine(type, machines));
for (el = machines; el; el = el->next) { if (machine_class) {
MachineClass *mc = el->data; type_print_class_properties(object_class_get_name(machine_class));
if (mc->alias) { return;
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)" : "");
} }
exit(0);
} }
mc = find_machine(name, machines); printf("Supported machines are:\n");
if (!mc) { machines = g_slist_sort(machines, machine_class_cmp);
error_report("unsupported machine type"); for (el = machines; el; el = el->next) {
error_printf("Use -machine help to list supported machines\n"); MachineClass *mc = el->data;
exit(1); 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; static const char *pid_file;
@ -1630,32 +1600,31 @@ static const QEMUOption *lookup_opt(int argc, char **argv,
return popt; 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); GSList *machines = object_class_get_list(TYPE_MACHINE, false);
MachineClass *machine_class = find_default_machine(machines); MachineClass *machine_class;
const char *optarg; Error *local_err = NULL;
QemuOpts *opts;
Location loc;
loc_push_none(&loc);
opts = qemu_get_machine_opts();
qemu_opts_loc_restore(opts);
optarg = qemu_opt_get(opts, "type");
if (optarg) { 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); 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; return machine_class;
} }
@ -1674,42 +1643,70 @@ static int object_parse_property_opt(Object *obj,
return 0; return 0;
} }
static int machine_set_property(void *opaque, /* *Non*recursively replace underscores with dashes in QDict keys. */
const char *name, const char *value, static void keyval_dashify(QDict *qdict, Error **errp)
Error **errp)
{ {
g_autofree char *qom_name = g_strdup(name); const QDictEntry *ent, *next;
char *p; char *p;
for (p = qom_name; *p; p++) { for (ent = qdict_first(qdict); ent; ent = next) {
if (*p == '_') { g_autofree char *new_key = NULL;
*p = '-';
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. */ /* Legacy options do not correspond to MachineState properties. */
if (g_str_equal(qom_name, "accel")) { value = qdict_get_try_str(qdict, "accel");
return 0; if (value) {
} accelerators = g_strdup(value);
if (g_str_equal(qom_name, "igd-passthru")) { qdict_del(qdict, "accel");
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;
} }
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 *)) 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; 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); MachineClass *machine_class = MACHINE_GET_CLASS(current_machine);
QemuOpts *machine_opts = qemu_get_machine_opts();
const char *boot_order = NULL; const char *boot_order = NULL;
const char *boot_once = NULL; const char *boot_once = NULL;
QemuOpts *opts; QemuOpts *opts;
qemu_opt_foreach(machine_opts, machine_set_property, current_machine, object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal);
&error_fatal);
current_machine->ram_size = ram_size; current_machine->ram_size = ram_size;
current_machine->maxram_size = maxram_size; current_machine->maxram_size = maxram_size;
current_machine->ram_slots = ram_slots; current_machine->ram_slots = ram_slots;
@ -1862,10 +1857,14 @@ static void qemu_apply_machine_options(void)
current_machine->boot_once = boot_once; current_machine->boot_once = boot_once;
if (semihosting_enabled() && !semihosting_get_argc()) { 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 */ /* 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 * Note: we need to create audio and block backends before
* machine_set_property(), so machine properties can refer to * setting machine properties, so they can be referred to.
* them.
*/ */
configure_blockdev(&bdo_queue, machine_class, snapshot); configure_blockdev(&bdo_queue, machine_class, snapshot);
audio_init_audiodevs(); audio_init_audiodevs();
@ -2088,16 +2086,14 @@ static void set_memory_options(MachineClass *mc)
loc_pop(&loc); 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); object_set_machine_compat_props(machine_class->compat_props);
set_memory_options(machine_class); set_memory_options(machine_class);
current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(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_property_add_child(object_get_root(), "machine",
OBJECT(current_machine)); OBJECT(current_machine));
object_property_add_child(container_get(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); 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 * Get the default machine options from the machine if it is not already
* specified either by the configuration file or by the command line. * specified either by the configuration file or by the command line.
*/ */
if (machine_class->default_machine_opts) { if (machine_class->default_machine_opts) {
qemu_opts_set_defaults(qemu_find_opts("machine"), QDict *default_opts =
machine_class->default_machine_opts, 0); 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) 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 false;
} }
return true; 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)); Visitor *v = qobject_input_visitor_new_keyval(QOBJECT(dict));
object_option_add_visitor(v); object_option_add_visitor(v);
visit_free(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 { } else {
abort(); abort();
} }
@ -2294,13 +2299,11 @@ static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp)
static void configure_accelerators(const char *progname) static void configure_accelerators(const char *progname)
{ {
const char *accelerators;
bool init_failed = false; bool init_failed = false;
qemu_opts_foreach(qemu_find_opts("icount"), qemu_opts_foreach(qemu_find_opts("icount"),
do_configure_icount, NULL, &error_fatal); do_configure_icount, NULL, &error_fatal);
accelerators = qemu_opt_get(qemu_get_machine_opts(), "accel");
if (QTAILQ_EMPTY(&qemu_accel_opts.head)) { if (QTAILQ_EMPTY(&qemu_accel_opts.head)) {
char **accel_list, **tmp; char **accel_list, **tmp;
@ -2388,12 +2391,11 @@ static void create_default_memdev(MachineState *ms, const char *path)
&error_fatal); &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 = qdict_get_try_str(machine_opts, "kernel");
const char *kernel_filename = qemu_opt_get(machine_opts, "kernel"); const char *initrd_filename = qdict_get_try_str(machine_opts, "initrd");
const char *initrd_filename = qemu_opt_get(machine_opts, "initrd"); const char *kernel_cmdline = qdict_get_try_str(machine_opts, "append");
const char *kernel_cmdline = qemu_opt_get(machine_opts, "append");
if (kernel_filename == NULL) { if (kernel_filename == NULL) {
if (kernel_cmdline != 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_add_opts(&qemu_trace_opts);
qemu_plugin_add_opts(); qemu_plugin_add_opts();
qemu_add_opts(&qemu_option_rom_opts); qemu_add_opts(&qemu_option_rom_opts);
qemu_add_opts(&qemu_machine_opts);
qemu_add_opts(&qemu_accel_opts); qemu_add_opts(&qemu_accel_opts);
qemu_add_opts(&qemu_mem_opts); qemu_add_opts(&qemu_mem_opts);
qemu_add_opts(&qemu_smp_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) { if (userconfig) {
qemu_read_default_config_file(&error_fatal); qemu_read_default_config_file(&error_fatal);
} }
@ -2863,8 +2865,7 @@ void qemu_init(int argc, char **argv, char **envp)
parse_display(optarg); parse_display(optarg);
break; break;
case QEMU_OPTION_nographic: case QEMU_OPTION_nographic:
olist = qemu_find_opts("machine"); qdict_put_str(machine_opts_dict, "graphics", "off");
qemu_opts_parse_noisily(olist, "graphics=off", false);
nographic = true; nographic = true;
dpy.type = DISPLAY_TYPE_NONE; dpy.type = DISPLAY_TYPE_NONE;
break; break;
@ -2888,16 +2889,16 @@ void qemu_init(int argc, char **argv, char **envp)
} }
break; break;
case QEMU_OPTION_kernel: case QEMU_OPTION_kernel:
qemu_opts_set(qemu_find_opts("machine"), "kernel", optarg, &error_abort); qdict_put_str(machine_opts_dict, "kernel", optarg);
break; break;
case QEMU_OPTION_initrd: case QEMU_OPTION_initrd:
qemu_opts_set(qemu_find_opts("machine"), "initrd", optarg, &error_abort); qdict_put_str(machine_opts_dict, "initrd", optarg);
break; break;
case QEMU_OPTION_append: case QEMU_OPTION_append:
qemu_opts_set(qemu_find_opts("machine"), "append", optarg, &error_abort); qdict_put_str(machine_opts_dict, "append", optarg);
break; break;
case QEMU_OPTION_dtb: case QEMU_OPTION_dtb:
qemu_opts_set(qemu_find_opts("machine"), "dtb", optarg, &error_abort); qdict_put_str(machine_opts_dict, "dtb", optarg);
break; break;
case QEMU_OPTION_cdrom: case QEMU_OPTION_cdrom:
drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS); drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
@ -3007,7 +3008,7 @@ void qemu_init(int argc, char **argv, char **envp)
} }
break; break;
case QEMU_OPTION_bios: case QEMU_OPTION_bios:
qemu_opts_set(qemu_find_opts("machine"), "firmware", optarg, &error_abort); qdict_put_str(machine_opts_dict, "firmware", optarg);
break; break;
case QEMU_OPTION_singlestep: case QEMU_OPTION_singlestep:
singlestep = 1; singlestep = 1;
@ -3234,6 +3235,8 @@ void qemu_init(int argc, char **argv, char **envp)
case QEMU_OPTION_no_quit: case QEMU_OPTION_no_quit:
dpy.has_window_close = true; dpy.has_window_close = true;
dpy.window_close = false; dpy.window_close = false;
warn_report("-no-quit is deprecated, please use "
"-display ...,window-close=off instead.");
break; break;
case QEMU_OPTION_sdl: case QEMU_OPTION_sdl:
#ifdef CONFIG_SDL #ifdef CONFIG_SDL
@ -3276,17 +3279,20 @@ void qemu_init(int argc, char **argv, char **envp)
preconfig_requested = true; preconfig_requested = true;
break; break;
case QEMU_OPTION_enable_kvm: case QEMU_OPTION_enable_kvm:
olist = qemu_find_opts("machine"); qdict_put_str(machine_opts_dict, "accel", "kvm");
qemu_opts_parse_noisily(olist, "accel=kvm", false);
break; break;
case QEMU_OPTION_M: case QEMU_OPTION_M:
case QEMU_OPTION_machine: case QEMU_OPTION_machine:
olist = qemu_find_opts("machine"); {
opts = qemu_opts_parse_noisily(olist, optarg, true); bool help;
if (!opts) {
exit(1); 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: case QEMU_OPTION_accel:
accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"), accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"),
optarg, true); optarg, true);
@ -3313,12 +3319,10 @@ void qemu_init(int argc, char **argv, char **envp)
} }
break; break;
case QEMU_OPTION_usb: case QEMU_OPTION_usb:
olist = qemu_find_opts("machine"); qdict_put_str(machine_opts_dict, "usb", "on");
qemu_opts_parse_noisily(olist, "usb=on", false);
break; break;
case QEMU_OPTION_usbdevice: case QEMU_OPTION_usbdevice:
olist = qemu_find_opts("machine"); qdict_put_str(machine_opts_dict, "usb", "on");
qemu_opts_parse_noisily(olist, "usb=on", false);
add_device_config(DEV_USB, optarg); add_device_config(DEV_USB, optarg);
break; break;
case QEMU_OPTION_device: case QEMU_OPTION_device:
@ -3328,21 +3332,16 @@ void qemu_init(int argc, char **argv, char **envp)
} }
break; break;
case QEMU_OPTION_smp: case QEMU_OPTION_smp:
if (!qemu_opts_parse_noisily(qemu_find_opts("smp-opts"), machine_parse_property_opt(qemu_find_opts("smp-opts"), "smp", optarg, &error_fatal);
optarg, true)) {
exit(1);
}
break; break;
case QEMU_OPTION_vnc: case QEMU_OPTION_vnc:
vnc_parse(optarg); vnc_parse(optarg);
break; break;
case QEMU_OPTION_no_acpi: case QEMU_OPTION_no_acpi:
olist = qemu_find_opts("machine"); qdict_put_str(machine_opts_dict, "acpi", "off");
qemu_opts_parse_noisily(olist, "acpi=off", false);
break; break;
case QEMU_OPTION_no_hpet: case QEMU_OPTION_no_hpet:
olist = qemu_find_opts("machine"); qdict_put_str(machine_opts_dict, "hpet", "off");
qemu_opts_parse_noisily(olist, "hpet=off", false);
break; break;
case QEMU_OPTION_no_reboot: case QEMU_OPTION_no_reboot:
olist = qemu_find_opts("action"); olist = qemu_find_opts("action");
@ -3595,7 +3594,7 @@ void qemu_init(int argc, char **argv, char **envp)
*/ */
loc_set_none(); loc_set_none();
qemu_validate_options(); qemu_validate_options(machine_opts_dict);
qemu_process_sugar_options(); qemu_process_sugar_options();
/* /*
@ -3628,7 +3627,7 @@ void qemu_init(int argc, char **argv, char **envp)
configure_rtc(qemu_find_opts_singleton("rtc")); configure_rtc(qemu_find_opts_singleton("rtc"));
qemu_create_machine(select_machine()); qemu_create_machine(machine_opts_dict);
suspend_mux_open(); suspend_mux_open();
@ -3636,12 +3635,14 @@ void qemu_init(int argc, char **argv, char **envp)
qemu_create_default_devices(); qemu_create_default_devices();
qemu_create_early_backends(); 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); phase_advance(PHASE_MACHINE_CREATED);
/* /*
* Note: uses machine properties such as kernel-irqchip, must run * Note: uses machine properties such as kernel-irqchip, must run
* after machine_set_property(). * after qemu_apply_machine_options.
*/ */
configure_accelerators(argv[0]); configure_accelerators(argv[0]);
phase_advance(PHASE_ACCEL_CREATED); phase_advance(PHASE_ACCEL_CREATED);

View File

@ -1304,53 +1304,37 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
}; };
#undef REGISTER #undef REGISTER
typedef struct ExtSaveArea { ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = {
uint32_t feature, bits;
uint32_t offset, size;
} ExtSaveArea;
static const ExtSaveArea x86_ext_save_areas[] = {
[XSTATE_FP_BIT] = { [XSTATE_FP_BIT] = {
/* x87 FP state component is always enabled if XSAVE is supported */ /* x87 FP state component is always enabled if XSAVE is supported */
.feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE, .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), .size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader),
}, },
[XSTATE_SSE_BIT] = { [XSTATE_SSE_BIT] = {
/* SSE state component is always enabled if XSAVE is supported */ /* SSE state component is always enabled if XSAVE is supported */
.feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE, .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), .size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader),
}, },
[XSTATE_YMM_BIT] = [XSTATE_YMM_BIT] =
{ .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX, { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
.offset = offsetof(X86XSaveArea, avx_state),
.size = sizeof(XSaveAVX) }, .size = sizeof(XSaveAVX) },
[XSTATE_BNDREGS_BIT] = [XSTATE_BNDREGS_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
.offset = offsetof(X86XSaveArea, bndreg_state),
.size = sizeof(XSaveBNDREG) }, .size = sizeof(XSaveBNDREG) },
[XSTATE_BNDCSR_BIT] = [XSTATE_BNDCSR_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
.offset = offsetof(X86XSaveArea, bndcsr_state),
.size = sizeof(XSaveBNDCSR) }, .size = sizeof(XSaveBNDCSR) },
[XSTATE_OPMASK_BIT] = [XSTATE_OPMASK_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
.offset = offsetof(X86XSaveArea, opmask_state),
.size = sizeof(XSaveOpmask) }, .size = sizeof(XSaveOpmask) },
[XSTATE_ZMM_Hi256_BIT] = [XSTATE_ZMM_Hi256_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
.offset = offsetof(X86XSaveArea, zmm_hi256_state),
.size = sizeof(XSaveZMM_Hi256) }, .size = sizeof(XSaveZMM_Hi256) },
[XSTATE_Hi16_ZMM_BIT] = [XSTATE_Hi16_ZMM_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
.offset = offsetof(X86XSaveArea, hi16_zmm_state),
.size = sizeof(XSaveHi16_ZMM) }, .size = sizeof(XSaveHi16_ZMM) },
[XSTATE_PKRU_BIT] = [XSTATE_PKRU_BIT] =
{ .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU,
.offset = offsetof(X86XSaveArea, pkru_state),
.size = sizeof(XSavePKRU) }, .size = sizeof(XSavePKRU) },
}; };

View File

@ -1305,41 +1305,23 @@ typedef struct XSavePKRU {
uint32_t padding; uint32_t padding;
} XSavePKRU; } 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(sizeof(XSaveAVX) != 0x100);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, bndreg_state) != 0x3c0);
QEMU_BUILD_BUG_ON(sizeof(XSaveBNDREG) != 0x40); 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(sizeof(XSaveBNDCSR) != 0x40);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, opmask_state) != 0x440);
QEMU_BUILD_BUG_ON(sizeof(XSaveOpmask) != 0x40); 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(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(sizeof(XSaveHi16_ZMM) != 0x400);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, pkru_state) != 0xA80);
QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8); 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 { typedef enum TPRAccess {
TPR_ACCESS_READ, TPR_ACCESS_READ,
TPR_ACCESS_WRITE, TPR_ACCESS_WRITE,
@ -1637,6 +1619,7 @@ typedef struct CPUX86State {
uint64_t apic_bus_freq; uint64_t apic_bus_freq;
#if defined(CONFIG_KVM) || defined(CONFIG_HVF) #if defined(CONFIG_KVM) || defined(CONFIG_HVF)
void *xsave_buf; void *xsave_buf;
uint32_t xsave_buf_len;
#endif #endif
#if defined(CONFIG_KVM) #if defined(CONFIG_KVM)
struct kvm_nested_state *nested_state; struct kvm_nested_state *nested_state;
@ -2197,8 +2180,8 @@ void x86_cpu_dump_local_apic_state(CPUState *cs, int flags);
/* cpu.c */ /* cpu.c */
bool cpu_is_bsp(X86CPU *cpu); bool cpu_is_bsp(X86CPU *cpu);
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);
void x86_cpu_xsave_all_areas(X86CPU *cpu, X86XSaveArea *buf); void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen);
void x86_update_hflags(CPUX86State* env); void x86_update_hflags(CPUX86State* env);
static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat) static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat)

View File

@ -30,6 +30,33 @@ static void hvf_cpu_max_instance_init(X86CPU *cpu)
hvf_get_supported_cpuid(0xC0000000, 0, R_EAX); 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) static void hvf_cpu_instance_init(CPUState *cs)
{ {
X86CPU *cpu = X86_CPU(cs); X86CPU *cpu = X86_CPU(cs);
@ -42,6 +69,8 @@ static void hvf_cpu_instance_init(CPUState *cs)
if (cpu->max_features) { if (cpu->max_features) {
hvf_cpu_max_instance_init(cpu); hvf_cpu_max_instance_init(cpu);
} }
hvf_cpu_xsave_init();
} }
static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data) static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data)

View File

@ -267,7 +267,14 @@ int hvf_arch_init_vcpu(CPUState *cpu)
wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, 0); wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, 0);
x86cpu = X86_CPU(cpu); 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_STAR, 1);
hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_LSTAR, 1); hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_LSTAR, 1);

View File

@ -73,14 +73,12 @@ void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg)
void hvf_put_xsave(CPUState *cpu_state) 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; if (hv_vcpu_write_fpstate(cpu_state->hvf->fd, xsave, xsave_len)) {
x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave);
if (hv_vcpu_write_fpstate(cpu_state->hvf->fd, (void*)xsave, 4096)) {
abort(); abort();
} }
} }
@ -158,15 +156,14 @@ void hvf_put_msrs(CPUState *cpu_state)
void hvf_get_xsave(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, xsave, xsave_len)) {
if (hv_vcpu_read_fpstate(cpu_state->hvf->fd, (void*)xsave, 4096)) {
abort(); 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) void hvf_get_segments(CPUState *cpu_state)

View File

@ -122,6 +122,34 @@ static void kvm_cpu_max_instance_init(X86CPU *cpu)
kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); 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) static void kvm_cpu_instance_init(CPUState *cs)
{ {
X86CPU *cpu = X86_CPU(cs); X86CPU *cpu = X86_CPU(cs);
@ -141,6 +169,8 @@ static void kvm_cpu_instance_init(CPUState *cs)
if (cpu->max_features) { if (cpu->max_features) {
kvm_cpu_max_instance_init(cpu); kvm_cpu_max_instance_init(cpu);
} }
kvm_cpu_xsave_init();
} }
static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data)

View File

@ -1888,8 +1888,16 @@ int kvm_arch_init_vcpu(CPUState *cs)
} }
if (has_xsave) { if (has_xsave) {
env->xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave)); env->xsave_buf_len = sizeof(struct kvm_xsave);
memset(env->xsave_buf, 0, 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(); 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); 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) static int kvm_put_xsave(X86CPU *cpu)
{ {
CPUX86State *env = &cpu->env; CPUX86State *env = &cpu->env;
X86XSaveArea *xsave = env->xsave_buf; void *xsave = env->xsave_buf;
if (!has_xsave) { if (!has_xsave) {
return kvm_put_fpu(cpu); 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); 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) static int kvm_get_xsave(X86CPU *cpu)
{ {
CPUX86State *env = &cpu->env; CPUX86State *env = &cpu->env;
X86XSaveArea *xsave = env->xsave_buf; void *xsave = env->xsave_buf;
int ret; int ret;
if (!has_xsave) { if (!has_xsave) {
@ -3169,7 +3138,7 @@ static int kvm_get_xsave(X86CPU *cpu)
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
x86_cpu_xrstor_all_areas(cpu, xsave); x86_cpu_xrstor_all_areas(cpu, xsave, env->xsave_buf_len);
return 0; return 0;
} }

View File

@ -20,6 +20,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include <math.h> #include <math.h>
#include "cpu.h" #include "cpu.h"
#include "tcg-cpu.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#include "fpu/softfloat.h" #include "fpu/softfloat.h"
#include "fpu/softfloat-macros.h" #include "fpu/softfloat-macros.h"

View File

@ -80,6 +80,24 @@ static void tcg_cpu_class_init(CPUClass *cc)
cc->init_accel_cpu = tcg_cpu_init_ops; 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 * 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); X86CPU *cpu = X86_CPU(cs);
/* Special cases not set in the X86CPUDefinition structs: */ /* Special cases not set in the X86CPUDefinition structs: */
x86_cpu_apply_props(cpu, tcg_default_props); x86_cpu_apply_props(cpu, tcg_default_props);
tcg_cpu_xsave_init();
} }
static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data)

View File

@ -19,6 +19,63 @@
#ifndef TCG_CPU_H #ifndef TCG_CPU_H
#define 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); bool tcg_cpu_realizefn(CPUState *cs, Error **errp);
#endif /* TCG_CPU_H */ #endif /* TCG_CPU_H */

View File

@ -6,14 +6,23 @@
#include "cpu.h" #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; CPUX86State *env = &cpu->env;
X86XSaveArea *xsave = buf; const ExtSaveArea *e, *f;
uint16_t cwd, swd, twd;
int i; 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; twd = 0;
swd = env->fpus & ~(7 << 11); swd = env->fpus & ~(7 << 11);
swd |= (env->fpstt & 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) { for (i = 0; i < 8; ++i) {
twd |= (!env->fptags[i]) << i; twd |= (!env->fptags[i]) << i;
} }
xsave->legacy.fcw = cwd; legacy->fcw = cwd;
xsave->legacy.fsw = swd; legacy->fsw = swd;
xsave->legacy.ftw = twd; legacy->ftw = twd;
xsave->legacy.fpop = env->fpop; legacy->fpop = env->fpop;
xsave->legacy.fpip = env->fpip; legacy->fpip = env->fpip;
xsave->legacy.fpdp = env->fpdp; legacy->fpdp = env->fpdp;
memcpy(&xsave->legacy.fpregs, env->fpregs, memcpy(&legacy->fpregs, env->fpregs,
sizeof env->fpregs); sizeof(env->fpregs));
xsave->legacy.mxcsr = env->mxcsr; 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);
for (i = 0; i < CPU_NB_REGS; i++) { for (i = 0; i < CPU_NB_REGS; i++) {
uint8_t *xmm = xsave->legacy.xmm_regs[i]; uint8_t *xmm = legacy->xmm_regs[i];
uint8_t *ymmh = xsave->avx_state.ymmh[i];
uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
stq_p(xmm, env->xmm_regs[i].ZMM_Q(0)); stq_p(xmm, env->xmm_regs[i].ZMM_Q(0));
stq_p(xmm+8, env->xmm_regs[i].ZMM_Q(1)); 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)); header->xstate_bv = env->xstate_bv;
stq_p(zmmh+8, env->xmm_regs[i].ZMM_Q(5));
stq_p(zmmh+16, env->xmm_regs[i].ZMM_Q(6)); e = &x86_ext_save_areas[XSTATE_YMM_BIT];
stq_p(zmmh+24, env->xmm_regs[i].ZMM_Q(7)); 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 #ifdef TARGET_X86_64
memcpy(&xsave->hi16_zmm_state.hi16_zmm, &env->xmm_regs[16], e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
16 * sizeof env->xmm_regs[16]); if (e->size && e->offset) {
memcpy(&xsave->pkru_state, &env->pkru, sizeof env->pkru); XSavePKRU *pkru = buf + e->offset;
#endif
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; CPUX86State *env = &cpu->env;
const X86XSaveArea *xsave = buf; const ExtSaveArea *e, *f, *g;
int i; int i;
const X86LegacyXSaveArea *legacy;
const X86XSaveHeader *header;
uint16_t cwd, swd, twd; uint16_t cwd, swd, twd;
cwd = xsave->legacy.fcw;
swd = xsave->legacy.fsw; e = &x86_ext_save_areas[XSTATE_FP_BIT];
twd = xsave->legacy.ftw;
env->fpop = xsave->legacy.fpop; 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->fpstt = (swd >> 11) & 7;
env->fpus = swd; env->fpus = swd;
env->fpuc = cwd; env->fpuc = cwd;
for (i = 0; i < 8; ++i) { for (i = 0; i < 8; ++i) {
env->fptags[i] = !((twd >> i) & 1); env->fptags[i] = !((twd >> i) & 1);
} }
env->fpip = xsave->legacy.fpip; env->fpip = legacy->fpip;
env->fpdp = xsave->legacy.fpdp; env->fpdp = legacy->fpdp;
env->mxcsr = xsave->legacy.mxcsr; env->mxcsr = legacy->mxcsr;
memcpy(env->fpregs, &xsave->legacy.fpregs, memcpy(env->fpregs, &legacy->fpregs,
sizeof env->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);
for (i = 0; i < CPU_NB_REGS; i++) { for (i = 0; i < CPU_NB_REGS; i++) {
const uint8_t *xmm = xsave->legacy.xmm_regs[i]; const uint8_t *xmm = legacy->xmm_regs[i];
const uint8_t *ymmh = xsave->avx_state.ymmh[i];
const uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm); 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(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->xstate_bv = header->xstate_bv;
env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh+8);
env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh+16); e = &x86_ext_save_areas[XSTATE_YMM_BIT];
env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh+24); 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 #ifdef TARGET_X86_64
memcpy(&env->xmm_regs[16], &xsave->hi16_zmm_state.hi16_zmm, e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
16 * sizeof env->xmm_regs[16]); if (e->size && e->offset) {
memcpy(&env->pkru, &xsave->pkru_state, sizeof env->pkru); const XSavePKRU *pkru;
#endif
pkru = buf + e->offset;
memcpy(&env->pkru, pkru, sizeof(env->pkru));
}
#endif
} }

View File

@ -25,7 +25,7 @@ static void test_mon_explicit(const void *data)
g_autofree char *s = NULL; g_autofree char *s = NULL;
g_autofree char *cli = 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"); "-numa node,nodeid=1,cpus=4-7");
qts = qtest_init(cli); 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 *s = NULL;
g_autofree char *cli = 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); qts = qtest_init(cli);
s = qtest_hmp(qts, "info numa"); 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 *s = NULL;
g_autofree char *cli = 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=0,memdev=ram,cpus=0-1 "
"-numa node,nodeid=1,cpus=4-5 "); "-numa node,nodeid=1,cpus=4-5 ");
qts = qtest_init(cli); qts = qtest_init(cli);
@ -86,7 +86,7 @@ static void test_query_cpus(const void *data)
QTestState *qts; QTestState *qts;
g_autofree char *cli = NULL; 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"); "-numa node,cpus=4-7");
qts = qtest_init(cli); qts = qtest_init(cli);
cpus = get_cpus(qts, &resp); cpus = get_cpus(qts, &resp);
@ -124,7 +124,7 @@ static void pc_numa_cpu(const void *data)
QTestState *qts; QTestState *qts;
g_autofree char *cli = NULL; 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 node,nodeid=0,memdev=ram -numa node,nodeid=1 "
"-numa cpu,node-id=1,socket-id=0 " "-numa cpu,node-id=1,socket-id=0 "
"-numa cpu,node-id=0,socket-id=1,core-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; QTestState *qts;
g_autofree char *cli = NULL; 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 node,nodeid=0,memdev=ram -numa node,nodeid=1 "
"-numa cpu,node-id=0,core-id=0 " "-numa cpu,node-id=0,core-id=0 "
"-numa cpu,node-id=0,core-id=1 " "-numa cpu,node-id=0,core-id=1 "
@ -222,7 +222,7 @@ static void aarch64_numa_cpu(const void *data)
QTestState *qts; QTestState *qts;
g_autofree char *cli = NULL; 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 node,nodeid=0,memdev=ram -numa node,nodeid=1 "
"-numa cpu,node-id=1,thread-id=0 " "-numa cpu,node-id=1,thread-id=0 "
"-numa cpu,node-id=0,thread-id=1"); "-numa cpu,node-id=0,thread-id=1");
@ -265,7 +265,7 @@ static void pc_dynamic_cpu_cfg(const void *data)
QTestState *qs; QTestState *qs;
g_autofree char *cli = NULL; 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); qs = qtest_init(cli);
/* create 2 numa nodes */ /* create 2 numa nodes */
@ -324,7 +324,7 @@ static void pc_hmat_build_cfg(const void *data)
g_autofree char *cli = NULL; g_autofree char *cli = NULL;
cli = make_cli(data, "-nodefaults --preconfig -machine hmat=on " 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 " "-m 128M,slots=2,maxmem=1G "
"-object memory-backend-ram,size=64M,id=m0 " "-object memory-backend-ram,size=64M,id=m0 "
"-object memory-backend-ram,size=64M,id=m1 " "-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; g_autofree char *cli = NULL;
cli = make_cli(data, "-nodefaults --preconfig " cli = make_cli(data, "-nodefaults --preconfig "
"-smp 2,sockets=2 " "-machine smp.cpus=2,smp.sockets=2 "
"-m 128M,slots=2,maxmem=1G " "-m 128M,slots=2,maxmem=1G "
"-object memory-backend-ram,size=64M,id=m0,prealloc=y " "-object memory-backend-ram,size=64M,id=m0,prealloc=y "
"-object memory-backend-ram,size=64M,id=m1 " "-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; g_autofree char *cli = NULL;
cli = make_cli(data, "-nodefaults --preconfig -machine hmat=on " 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 " "-m 128M,slots=2,maxmem=1G "
"-object memory-backend-ram,size=64M,id=m0 " "-object memory-backend-ram,size=64M,id=m0 "
"-object memory-backend-ram,size=64M,id=m1 " "-object memory-backend-ram,size=64M,id=m1 "

View File

@ -747,6 +747,61 @@ static void test_keyval_visit_any(void)
visit_free(v); 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[]) int main(int argc, char *argv[])
{ {
g_test_init(&argc, &argv, NULL); 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/optional", test_keyval_visit_optional);
g_test_add_func("/keyval/visit/alternate", test_keyval_visit_alternate); 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/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(); g_test_run();
return 0; return 0;
} }

View File

@ -410,40 +410,6 @@ static void test_qemu_opts_reset(void)
g_assert(opts == NULL); 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, static int opts_count_iter(void *opaque, const char *name, const char *value,
Error **errp) 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_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/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_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/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/bool", test_opts_parse_bool);
g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number); g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);

View File

@ -310,6 +310,86 @@ static char *reassemble_key(GSList *key)
return g_string_free(s, FALSE); 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. * Listify @cur recursively.
* Replace QDicts whose keys are all valid list indexes by QLists. * 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 not NULL, store whether help is requested there.
* If @p_help is NULL and help is requested, fail. * If @p_help is NULL and help is requested, fail.
* *
* On success, return a dictionary of the parsed keys and values. * On success, return @dict, now filled with the parsed keys and values.
* On failure, store an error through @errp and return NULL. *
* 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, QDict *keyval_parse_into(QDict *qdict, const char *params, const char *implied_key,
bool *p_help, Error **errp) bool *p_help, Error **errp)
{ {
QDict *qdict = qdict_new();
QObject *listified; QObject *listified;
const char *s; const char *s;
bool help = false; bool help = false;
@ -446,7 +527,6 @@ QDict *keyval_parse(const char *params, const char *implied_key,
while (*s) { while (*s) {
s = keyval_parse_one(qdict, s, implied_key, &help, errp); s = keyval_parse_one(qdict, s, implied_key, &help, errp);
if (!s) { if (!s) {
qobject_unref(qdict);
return NULL; return NULL;
} }
implied_key = NULL; implied_key = NULL;
@ -456,15 +536,42 @@ QDict *keyval_parse(const char *params, const char *implied_key,
*p_help = help; *p_help = help;
} else if (help) { } else if (help) {
error_setg(errp, "Help is not available for this option"); error_setg(errp, "Help is not available for this option");
qobject_unref(qdict);
return NULL; return NULL;
} }
listified = keyval_listify(qdict, NULL, errp); listified = keyval_listify(qdict, NULL, errp);
if (!listified) { if (!listified) {
qobject_unref(qdict);
return NULL; return NULL;
} }
assert(listified == QOBJECT(qdict)); assert(listified == QOBJECT(qdict));
return 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;
}

View File

@ -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(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_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('aio-posix.c'))
util_ss.add(when: 'CONFIG_POSIX', if_true: files('fdmon-poll.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_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('compatfd.c'))
util_ss.add(when: 'CONFIG_POSIX', if_true: files('event_notifier-posix.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('event_notifier-posix.c'))

View File

@ -479,19 +479,14 @@ int qemu_opt_unset(QemuOpts *opts, const char *name)
} }
} }
static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value, static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value)
bool prepend)
{ {
QemuOpt *opt = g_malloc0(sizeof(*opt)); QemuOpt *opt = g_malloc0(sizeof(*opt));
opt->name = g_strdup(name); opt->name = g_strdup(name);
opt->str = value; opt->str = value;
opt->opts = opts; opt->opts = opts;
if (prepend) { QTAILQ_INSERT_TAIL(&opts->head, opt, next);
QTAILQ_INSERT_HEAD(&opts->head, opt, next);
} else {
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
}
return opt; 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, bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
Error **errp) 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)) { if (!opt_validate(opt, errp)) {
qemu_opt_del(opt); qemu_opt_del(opt);
@ -662,15 +657,6 @@ void qemu_opts_loc_restore(QemuOpts *opts)
loc_restore(&opts->loc); 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) const char *qemu_opts_id(QemuOpts *opts)
{ {
return opts->id; 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, 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) bool warn_on_flag, bool *help_wanted, Error **errp)
{ {
char *option, *value; char *option, *value;
@ -833,7 +819,7 @@ static bool opts_do_parse(QemuOpts *opts, const char *params,
continue; continue;
} }
opt = opt_create(opts, option, value, prepend); opt = opt_create(opts, option, value);
g_free(option); g_free(option);
if (!opt_validate(opt, errp)) { if (!opt_validate(opt, errp)) {
qemu_opt_del(opt); 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, bool qemu_opts_do_parse(QemuOpts *opts, const char *params,
const char *firstname, Error **errp) 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, 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) bool warn_on_flag, bool *help_wanted, Error **errp)
{ {
const char *firstname; const char *firstname;
@ -903,21 +889,13 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
assert(!permit_abbrev || list->implied_opt_name); assert(!permit_abbrev || list->implied_opt_name);
firstname = permit_abbrev ? list->implied_opt_name : NULL; 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); opts = qemu_opts_create(list, id, !list->merge_lists, errp);
g_free(id); g_free(id);
if (opts == NULL) { if (opts == NULL) {
return NULL; return NULL;
} }
if (!opts_do_parse(opts, params, firstname, defaults, if (!opts_do_parse(opts, params, firstname,
warn_on_flag, help_wanted, errp)) { warn_on_flag, help_wanted, errp)) {
qemu_opts_del(opts); qemu_opts_del(opts);
return NULL; return NULL;
@ -936,7 +914,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
bool permit_abbrev, Error **errp) 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; QemuOpts *opts;
bool help_wanted = false; 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, opts_accepts_any(list) ? NULL : &help_wanted,
&err); &err);
if (!opts) { if (!opts) {
@ -968,15 +946,6 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
return opts; 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, static bool qemu_opts_from_qdict_entry(QemuOpts *opts,
const QDictEntry *entry, const QDictEntry *entry,
Error **errp) Error **errp)