diff --git a/MAINTAINERS b/MAINTAINERS index 81aa31b5e1..37c0110d88 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2189,6 +2189,7 @@ F: tests/qtest/prom-env-test.c VM Generation ID S: Orphan +R: Ani Sinha F: hw/acpi/vmgenid.c F: include/hw/acpi/vmgenid.h F: docs/specs/vmgenid.txt @@ -2204,6 +2205,7 @@ F: hw/misc/led.c Unimplemented device M: Peter Maydell R: Philippe Mathieu-Daudé +R: Ani Sinha S: Maintained F: include/hw/misc/unimp.h F: hw/misc/unimp.c @@ -2211,6 +2213,7 @@ F: hw/misc/unimp.c Empty slot M: Artyom Tarasenko R: Philippe Mathieu-Daudé +R: Ani Sinha S: Maintained F: include/hw/misc/empty_slot.h F: hw/misc/empty_slot.c @@ -2413,6 +2416,7 @@ F: audio/alsaaudio.c Core Audio framework backend M: Gerd Hoffmann R: Christian Schoenebeck +R: Akihiko Odaki S: Odd Fixes F: audio/coreaudio.c @@ -2665,6 +2669,7 @@ F: util/drm.c Cocoa graphics M: Peter Maydell +R: Akihiko Odaki S: Odd Fixes F: ui/cocoa.m @@ -2985,10 +2990,11 @@ F: docs/sphinx/fakedbusdoc.py F: tests/qtest/dbus* Seccomp -M: Eduardo Otubo -S: Supported +M: Daniel P. Berrange +S: Odd Fixes F: softmmu/qemu-seccomp.c F: include/sysemu/seccomp.h +F: tests/unit/test-seccomp.c Cryptography M: Daniel P. Berrange diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 1879a35654..c1625b4f1d 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -51,6 +51,7 @@ #include "qemu/qemu-print.h" #include "qemu/timer.h" #include "qemu/main-loop.h" +#include "qemu/cacheinfo.h" #include "exec/log.h" #include "sysemu/cpus.h" #include "sysemu/cpu-timers.h" diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index cd038024fa..25141283c4 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -14,6 +14,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" +#include "qemu/madvise.h" #include "sysemu/hostmem.h" #include "qom/object_interfaces.h" #include "qom/object.h" diff --git a/backends/hostmem.c b/backends/hostmem.c index 4c05862ed5..b2a5e905e8 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -19,6 +19,7 @@ #include "qemu/config-file.h" #include "qom/object_interfaces.h" #include "qemu/mmap-alloc.h" +#include "qemu/madvise.h" #ifdef CONFIG_NUMA #include diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build index 857929082e..7f2503f84e 100644 --- a/backends/tpm/meson.build +++ b/backends/tpm/meson.build @@ -1,8 +1,6 @@ -tpm_ss = ss.source_set() - -tpm_ss.add(files('tpm_backend.c')) -tpm_ss.add(files('tpm_util.c')) -tpm_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: files('tpm_passthrough.c')) -tpm_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c')) - -softmmu_ss.add_all(when: 'CONFIG_TPM', if_true: tpm_ss) +if have_tpm + softmmu_ss.add(files('tpm_backend.c')) + softmmu_ss.add(files('tpm_util.c')) + softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: files('tpm_passthrough.c')) + softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c')) +endif diff --git a/block/meson.build b/block/meson.build index 90dc9983e5..8a1ce58c9c 100644 --- a/block/meson.build +++ b/block/meson.build @@ -45,25 +45,44 @@ block_ss.add(files( softmmu_ss.add(when: 'CONFIG_TCG', if_true: files('blkreplay.c')) -block_ss.add(when: 'CONFIG_QCOW1', if_true: files('qcow.c')) -block_ss.add(when: 'CONFIG_VDI', if_true: files('vdi.c')) -block_ss.add(when: 'CONFIG_CLOOP', if_true: files('cloop.c')) -block_ss.add(when: 'CONFIG_BOCHS', if_true: files('bochs.c')) -block_ss.add(when: 'CONFIG_VVFAT', if_true: files('vvfat.c')) -block_ss.add(when: 'CONFIG_DMG', if_true: files('dmg.c')) -block_ss.add(when: 'CONFIG_QED', if_true: files( - 'qed-check.c', - 'qed-cluster.c', - 'qed-l2-cache.c', - 'qed-table.c', - 'qed.c', -)) -block_ss.add(when: 'CONFIG_PARALLELS', if_true: files('parallels.c', 'parallels-ext.c')) +if get_option('qcow1').allowed() + block_ss.add(files('qcow.c')) +endif +if get_option('vdi').allowed() + block_ss.add(files('vdi.c')) +endif +if get_option('cloop').allowed() + block_ss.add(files('cloop.c')) +endif +if get_option('bochs').allowed() + block_ss.add(files('bochs.c')) +endif +if get_option('vvfat').allowed() + block_ss.add(files('vvfat.c')) +endif +if get_option('dmg').allowed() + block_ss.add(files('dmg.c')) +endif +if get_option('qed').allowed() + block_ss.add(files( + 'qed-check.c', + 'qed-cluster.c', + 'qed-l2-cache.c', + 'qed-table.c', + 'qed.c', + )) +endif +if get_option('parallels').allowed() + block_ss.add(files('parallels.c', 'parallels-ext.c')) +endif + block_ss.add(when: 'CONFIG_WIN32', if_true: files('file-win32.c', 'win32-aio.c')) block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit]) block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c')) block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c')) -block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c')) +if not get_option('replication').disabled() + block_ss.add(files('replication.c')) +endif block_ss.add(when: libaio, if_true: files('linux-aio.c')) block_ss.add(when: linux_io_uring, if_true: files('io_uring.c')) @@ -89,7 +108,7 @@ foreach m : [ endforeach # those are not exactly regular block modules, so treat them apart -if 'CONFIG_DMG' in config_host +if get_option('dmg').allowed() foreach m : [ [liblzfse, 'dmg-lzfse', liblzfse, 'dmg-lzfse.c'], [libbzip2, 'dmg-bz2', [glib, libbzip2], 'dmg-bz2.c'] diff --git a/block/ssh.c b/block/ssh.c index 3b5bf34031..a64db146db 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -386,14 +386,28 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len, return *host_key_check - '\0'; } +static char *format_fingerprint(const unsigned char *fingerprint, size_t len) +{ + static const char *hex = "0123456789abcdef"; + char *ret = g_new0(char, (len * 2) + 1); + for (size_t i = 0; i < len; i++) { + ret[i * 2] = hex[((fingerprint[i] >> 4) & 0xf)]; + ret[(i * 2) + 1] = hex[(fingerprint[i] & 0xf)]; + } + ret[len * 2] = '\0'; + return ret; +} + static int check_host_key_hash(BDRVSSHState *s, const char *hash, - enum ssh_publickey_hash_type type, Error **errp) + enum ssh_publickey_hash_type type, const char *typestr, + Error **errp) { int r; ssh_key pubkey; unsigned char *server_hash; size_t server_hash_len; + const char *keytype; r = ssh_get_server_publickey(s->session, &pubkey); if (r != SSH_OK) { @@ -401,6 +415,8 @@ check_host_key_hash(BDRVSSHState *s, const char *hash, return -EINVAL; } + keytype = ssh_key_type_to_char(ssh_key_type(pubkey)); + r = ssh_get_publickey_hash(pubkey, type, &server_hash, &server_hash_len); ssh_key_free(pubkey); if (r != 0) { @@ -410,12 +426,16 @@ check_host_key_hash(BDRVSSHState *s, const char *hash, } r = compare_fingerprint(server_hash, server_hash_len, hash); - ssh_clean_pubkey_hash(&server_hash); if (r != 0) { - error_setg(errp, "remote host key does not match host_key_check '%s'", - hash); + g_autofree char *server_fp = format_fingerprint(server_hash, + server_hash_len); + error_setg(errp, "remote host %s key fingerprint '%s:%s' " + "does not match host_key_check '%s:%s'", + keytype, typestr, server_fp, typestr, hash); + ssh_clean_pubkey_hash(&server_hash); return -EPERM; } + ssh_clean_pubkey_hash(&server_hash); return 0; } @@ -436,13 +456,16 @@ static int check_host_key(BDRVSSHState *s, SshHostKeyCheck *hkc, Error **errp) case SSH_HOST_KEY_CHECK_MODE_HASH: if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) { return check_host_key_hash(s, hkc->u.hash.hash, - SSH_PUBLICKEY_HASH_MD5, errp); + SSH_PUBLICKEY_HASH_MD5, "md5", + errp); } else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) { return check_host_key_hash(s, hkc->u.hash.hash, - SSH_PUBLICKEY_HASH_SHA1, errp); + SSH_PUBLICKEY_HASH_SHA1, "sha1", + errp); } else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA256) { return check_host_key_hash(s, hkc->u.hash.hash, - SSH_PUBLICKEY_HASH_SHA256, errp); + SSH_PUBLICKEY_HASH_SHA256, "sha256", + errp); } g_assert_not_reached(); break; @@ -556,6 +579,11 @@ static bool ssh_process_legacy_options(QDict *output_opts, qdict_put_str(output_opts, "host-key-check.type", "sha1"); qdict_put_str(output_opts, "host-key-check.hash", &host_key_check[5]); + } else if (strncmp(host_key_check, "sha256:", 7) == 0) { + qdict_put_str(output_opts, "host-key-check.mode", "hash"); + qdict_put_str(output_opts, "host-key-check.type", "sha256"); + qdict_put_str(output_opts, "host-key-check.hash", + &host_key_check[7]); } else if (strcmp(host_key_check, "yes") == 0) { qdict_put_str(output_opts, "host-key-check.mode", "known_hosts"); } else { diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 0bc6d2edbd..8a36b696d8 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu.h" #include "signal-common.h" #include "trace.h" diff --git a/configure b/configure index 73265b7690..9fe2a6a6ad 100755 --- a/configure +++ b/configure @@ -238,9 +238,7 @@ cross_prefix="" audio_drv_list="default" block_drv_rw_whitelist="" block_drv_ro_whitelist="" -block_drv_whitelist_tools="no" host_cc="cc" -libs_qga="" debug_info="yes" lto="false" stack_protector="" @@ -290,7 +288,6 @@ EXTRA_CXXFLAGS="" EXTRA_LDFLAGS="" xen_ctrl_version="$default_feature" -membarrier="$default_feature" vhost_kernel="$default_feature" vhost_net="$default_feature" vhost_crypto="$default_feature" @@ -301,7 +298,6 @@ vhost_user_fs="$default_feature" vhost_vdpa="$default_feature" rdma="$default_feature" pvrdma="$default_feature" -gprof="no" debug_tcg="no" debug="no" sanitizers="no" @@ -313,57 +309,36 @@ modules="no" module_upgrades="no" prefix="/usr/local" qemu_suffix="qemu" -profiler="no" softmmu="yes" linux_user="" bsd_user="" pkgversion="" pie="" -qom_cast_debug="yes" trace_backends="log" trace_file="trace" opengl="$default_feature" -cpuid_h="no" -avx2_opt="$default_feature" -guest_agent="$default_feature" -vss_win32_sdk="$default_feature" -win_sdk="no" -want_tools="$default_feature" coroutine="" -coroutine_pool="$default_feature" -debug_stack_usage="no" -crypto_afalg="no" tls_priority="NORMAL" -tpm="$default_feature" -live_block_migration=${default_feature:-yes} -numa="$default_feature" -replication=${default_feature:-yes} -bochs=${default_feature:-yes} -cloop=${default_feature:-yes} -dmg=${default_feature:-yes} -qcow1=${default_feature:-yes} -vdi=${default_feature:-yes} -vvfat=${default_feature:-yes} -qed=${default_feature:-yes} -parallels=${default_feature:-yes} -debug_mutex="no" plugins="$default_feature" -rng_none="no" secret_keyring="$default_feature" meson="" meson_args="" ninja="" gio="$default_feature" skip_meson=no -slirp_smbd="$default_feature" # The following Meson options are handled manually (still they # are included in the automatically generated help message) # 1. Track which submodules are needed -capstone="auto" +if test "$default_feature" = no ; then + capstone="disabled" + slirp="disabled" +else + capstone="auto" + slirp="auto" +fi fdt="auto" -slirp="auto" # 2. Support --with/--without option default_devices="true" @@ -441,6 +416,7 @@ objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" ranlib="${RANLIB-${cross_prefix}ranlib}" nm="${NM-${cross_prefix}nm}" +smbd="$SMBD" strip="${STRIP-${cross_prefix}strip}" windres="${WINDRES-${cross_prefix}windres}" pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}" @@ -560,7 +536,6 @@ darwin) sunos) solaris="yes" make="${MAKE-gmake}" - smbd="${SMBD-/usr/sfw/sbin/smbd}" # needed for CMSG_ macros in sys/socket.h QEMU_CFLAGS="-D_XOPEN_SOURCE=600 $QEMU_CFLAGS" # needed for TIOCWIN* defines in termios.h @@ -714,7 +689,6 @@ if test "$mingw32" = "yes" ; then write_c_skeleton; prefix="/qemu" qemu_suffix="" - libs_qga="-lws2_32 -lwinmm -lpowrprof -lwtsapi32 -lwininet -liphlpapi -lnetapi32 $libs_qga" fi werror="" @@ -826,8 +800,6 @@ for opt do ;; --without-default-features) # processed above ;; - --enable-gprof) gprof="yes" - ;; --enable-gcov) gcov="yes" ;; --static) @@ -868,20 +840,12 @@ for opt do # configure to be used by RPM and similar macros that set # lots of directory switches by default. ;; - --disable-qom-cast-debug) qom_cast_debug="no" - ;; - --enable-qom-cast-debug) qom_cast_debug="yes" - ;; --audio-drv-list=*) audio_drv_list="$optarg" ;; --block-drv-rw-whitelist=*|--block-drv-whitelist=*) block_drv_rw_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') ;; --block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') ;; - --enable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="yes" - ;; - --disable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="no" - ;; --enable-debug-tcg) debug_tcg="yes" ;; --disable-debug-tcg) debug_tcg="no" @@ -889,7 +853,7 @@ for opt do --enable-debug) # Enable debugging options that aren't excessively noisy debug_tcg="yes" - debug_mutex="yes" + meson_option_parse --enable-debug-mutex "" debug="yes" fortify_source="no" ;; @@ -918,8 +882,6 @@ for opt do ;; --enable-tcg) tcg="enabled" ;; - --enable-profiler) profiler="yes" - ;; --disable-system) softmmu="no" ;; --enable-system) softmmu="yes" @@ -971,24 +933,10 @@ for opt do ;; --enable-fdt=*) fdt="$optarg" ;; - --disable-membarrier) membarrier="no" - ;; - --enable-membarrier) membarrier="yes" - ;; --with-pkgversion=*) pkgversion="$optarg" ;; --with-coroutine=*) coroutine="$optarg" ;; - --disable-coroutine-pool) coroutine_pool="no" - ;; - --enable-coroutine-pool) coroutine_pool="yes" - ;; - --enable-debug-stack-usage) debug_stack_usage="yes" - ;; - --enable-crypto-afalg) crypto_afalg="yes" - ;; - --disable-crypto-afalg) crypto_afalg="no" - ;; --disable-vhost-net) vhost_net="no" ;; --enable-vhost-net) vhost_net="yes" @@ -1015,34 +963,6 @@ for opt do ;; --disable-zlib-test) ;; - --enable-guest-agent) guest_agent="yes" - ;; - --disable-guest-agent) guest_agent="no" - ;; - --with-vss-sdk) vss_win32_sdk="" - ;; - --with-vss-sdk=*) vss_win32_sdk="$optarg" - ;; - --without-vss-sdk) vss_win32_sdk="no" - ;; - --with-win-sdk) win_sdk="" - ;; - --with-win-sdk=*) win_sdk="$optarg" - ;; - --without-win-sdk) win_sdk="no" - ;; - --enable-tools) want_tools="yes" - ;; - --disable-tools) want_tools="no" - ;; - --disable-avx2) avx2_opt="no" - ;; - --enable-avx2) avx2_opt="yes" - ;; - --disable-avx512f) avx512f_opt="no" - ;; - --enable-avx512f) avx512f_opt="yes" - ;; --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane) echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2 ;; @@ -1062,54 +982,6 @@ for opt do ;; --disable-pvrdma) pvrdma="no" ;; - --disable-tpm) tpm="no" - ;; - --enable-tpm) tpm="yes" - ;; - --disable-live-block-migration) live_block_migration="no" - ;; - --enable-live-block-migration) live_block_migration="yes" - ;; - --disable-numa) numa="no" - ;; - --enable-numa) numa="yes" - ;; - --disable-replication) replication="no" - ;; - --enable-replication) replication="yes" - ;; - --disable-bochs) bochs="no" - ;; - --enable-bochs) bochs="yes" - ;; - --disable-cloop) cloop="no" - ;; - --enable-cloop) cloop="yes" - ;; - --disable-dmg) dmg="no" - ;; - --enable-dmg) dmg="yes" - ;; - --disable-qcow1) qcow1="no" - ;; - --enable-qcow1) qcow1="yes" - ;; - --disable-vdi) vdi="no" - ;; - --enable-vdi) vdi="yes" - ;; - --disable-vvfat) vvfat="no" - ;; - --enable-vvfat) vvfat="yes" - ;; - --disable-qed) qed="no" - ;; - --enable-qed) qed="yes" - ;; - --disable-parallels) parallels="no" - ;; - --enable-parallels) parallels="yes" - ;; --disable-vhost-user) vhost_user="no" ;; --enable-vhost-user) vhost_user="yes" @@ -1135,10 +1007,6 @@ for opt do --with-git-submodules=*) git_submodules_action="$optarg" ;; - --enable-debug-mutex) debug_mutex=yes - ;; - --disable-debug-mutex) debug_mutex=no - ;; --enable-plugins) if test "$mingw32" = "yes"; then error_exit "TCG plugins not currently supported on Windows platforms" else @@ -1153,10 +1021,6 @@ for opt do ;; --gdb=*) gdb_bin="$optarg" ;; - --enable-rng-none) rng_none=yes - ;; - --disable-rng-none) rng_none=no - ;; --enable-keyring) secret_keyring="yes" ;; --disable-keyring) secret_keyring="no" @@ -1165,10 +1029,6 @@ for opt do ;; --disable-gio) gio=no ;; - --enable-slirp-smbd) slirp_smbd=yes - ;; - --disable-slirp-smbd) slirp_smbd=no - ;; # backwards compatibility options --enable-trace-backend=*) meson_option_parse "--enable-trace-backends=$optarg" "$optarg" ;; @@ -1369,21 +1229,13 @@ Advanced options (experts only): --block-drv-ro-whitelist=L set block driver read-only whitelist (by default affects only QEMU, not tools like qemu-img) - --enable-block-drv-whitelist-in-tools - use block whitelist also in tools instead of only QEMU --with-trace-file=NAME Full PATH,NAME of file to store traces Default:trace- --cpu=CPU Build for host CPU [$cpu] --with-coroutine=BACKEND coroutine backend. Supported options: ucontext, sigaltstack, windows --enable-gcov enable test coverage analysis with gcov - --with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent - --with-win-sdk=SDK-path path to Windows Platform SDK (to build VSS .tlb) --tls-priority default TLS protocol/cipher priority string - --enable-gprof QEMU profiling with gprof - --enable-profiler profiler support - --enable-debug-stack-usage - track the maximum stack usage of stacks created by qemu_alloc_stack --enable-plugins enable plugins via shared library loading --disable-containers don't use containers for cross-building @@ -1395,7 +1247,6 @@ cat << EOF user supported user emulation targets linux-user all linux usermode emulation targets bsd-user all BSD usermode emulation targets - guest-agent build the QEMU Guest Agent pie Position Independent Executables modules modules support (non-Windows) module-upgrades try to load modules from alternate paths for upgrades @@ -1404,7 +1255,6 @@ cat << EOF lto Enable Link-Time Optimization. safe-stack SafeStack Stack Smash Protection. Depends on clang/llvm >= 3.7 and requires coroutine backend ucontext. - membarrier membarrier system call (for Linux 4.14+ or Windows) rdma Enable RDMA-based migration pvrdma Enable PVRDMA support vhost-net vhost-net kernel acceleration support @@ -1414,29 +1264,8 @@ cat << EOF vhost-kernel vhost kernel backend support vhost-user vhost-user backend support vhost-vdpa vhost-vdpa kernel backend support - live-block-migration Block migration in the main migration stream - coroutine-pool coroutine freelist (better performance) - tpm TPM support - numa libnuma support - avx2 AVX2 optimization support - avx512f AVX512F optimization support - replication replication support opengl opengl support - qom-cast-debug cast debugging support - tools build qemu-io, qemu-nbd and qemu-img tools - bochs bochs image format support - cloop cloop image format support - dmg dmg image format support - qcow1 qcow v1 image format support - vdi vdi image format support - vvfat vvfat image format support - qed qed image format support - parallels parallels image format support - crypto-afalg Linux AF_ALG crypto backend driver - debug-mutex mutex debugging support - rng-none dummy RNG, avoid using /dev/(u)random and getrandom() gio libgio support - slirp-smbd use smbd (at path --smbd=*) in slirp networking NOTE: The object files are built at the place where configure is launched EOF @@ -1838,16 +1667,6 @@ else exit 1 fi -########################################## -# system tools -if test -z "$want_tools"; then - if test "$softmmu" = "no"; then - want_tools=no - else - want_tools=yes - fi -fi - ######################################### # vhost interdependencies and host support @@ -2437,21 +2256,6 @@ if test "$modules" = yes; then fi fi -########################################## -# TPM emulation is only on POSIX - -if test "$tpm" = ""; then - if test "$mingw32" = "yes"; then - tpm=no - else - tpm=yes - fi -elif test "$tpm" = "yes"; then - if test "$mingw32" = "yes" ; then - error_exit "TPM emulation only available on POSIX systems" - fi -fi - ########################################## # fdt probe @@ -2491,26 +2295,6 @@ EOF fi fi -########################################## -# libnuma probe - -if test "$numa" != "no" ; then - cat > $TMPC << EOF -#include -int main(void) { return numa_available(); } -EOF - - if compile_prog "" "-lnuma" ; then - numa=yes - numa_libs="-lnuma" - else - if test "$numa" = "yes" ; then - feature_not_found "numa" "install numactl devel" - fi - numa=no - fi -fi - # check for usbfs have_usbfs=no if test "$linux_user" = "yes"; then @@ -2535,85 +2319,6 @@ EOF fi fi -########################################## -# check if we have VSS SDK headers for win - -guest_agent_with_vss="no" -if test "$mingw32" = "yes" && test "$guest_agent" != "no" && \ - test "$vss_win32_sdk" != "no" ; then - case "$vss_win32_sdk" in - "") vss_win32_include="-isystem $source_path" ;; - *\ *) # The SDK is installed in "Program Files" by default, but we cannot - # handle path with spaces. So we symlink the headers into ".sdk/vss". - vss_win32_include="-isystem $source_path/.sdk/vss" - symlink "$vss_win32_sdk/inc" "$source_path/.sdk/vss/inc" - ;; - *) vss_win32_include="-isystem $vss_win32_sdk" - esac - cat > $TMPC << EOF -#define __MIDL_user_allocate_free_DEFINED__ -#include -int main(void) { return VSS_CTX_BACKUP; } -EOF - if compile_prog "$vss_win32_include" "" ; then - guest_agent_with_vss="yes" - QEMU_CFLAGS="$QEMU_CFLAGS $vss_win32_include" - libs_qga="-lole32 -loleaut32 -lshlwapi -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga" - qga_vss_provider="qga/vss-win32/qga-vss.dll qga/vss-win32/qga-vss.tlb" - else - if test "$vss_win32_sdk" != "" ; then - echo "ERROR: Please download and install Microsoft VSS SDK:" - echo "ERROR: http://www.microsoft.com/en-us/download/details.aspx?id=23490" - echo "ERROR: On POSIX-systems, you can extract the SDK headers by:" - echo "ERROR: scripts/extract-vsssdk-headers setup.exe" - echo "ERROR: The headers are extracted in the directory \`inc'." - feature_not_found "VSS support" - fi - fi -fi - -########################################## -# lookup Windows platform SDK (if not specified) -# The SDK is needed only to build .tlb (type library) file of guest agent -# VSS provider from the source. It is usually unnecessary because the -# pre-compiled .tlb file is included. - -if test "$mingw32" = "yes" && test "$guest_agent" != "no" && \ - test "$guest_agent_with_vss" = "yes" ; then - if test -z "$win_sdk"; then - programfiles="$PROGRAMFILES" - test -n "$PROGRAMW6432" && programfiles="$PROGRAMW6432" - if test -n "$programfiles"; then - win_sdk=$(ls -d "$programfiles/Microsoft SDKs/Windows/v"* | tail -1) 2>/dev/null - else - feature_not_found "Windows SDK" - fi - elif test "$win_sdk" = "no"; then - win_sdk="" - fi -fi - -########################################## -# check if mingw environment provides a recent ntddscsi.h -guest_agent_ntddscsi="no" -if test "$mingw32" = "yes" && test "$guest_agent" != "no"; then - cat > $TMPC << EOF -#include -#include -int main(void) { -#if !defined(IOCTL_SCSI_GET_ADDRESS) -#error Missing required ioctl definitions -#endif - SCSI_ADDRESS addr = { .Lun = 0, .TargetId = 0, .PathId = 0 }; - return addr.Lun; -} -EOF - if compile_prog "" "" ; then - guest_agent_ntddscsi=yes - libs_qga="-lsetupapi -lcfgmgr32 $libs_qga" - fi -fi - ########################################## # capstone @@ -2679,17 +2384,6 @@ else esac fi -if test "$coroutine_pool" = ""; then - coroutine_pool=yes -fi - -if test "$debug_stack_usage" = "yes"; then - if test "$coroutine_pool" = "yes"; then - echo "WARN: disabling coroutine pool for stack usage debugging" - coroutine_pool=no - fi -fi - ################################################## # SafeStack @@ -2752,85 +2446,6 @@ else # "$safe_stack" = "" fi fi -######################################## -# check if cpuid.h is usable. - -cat > $TMPC << EOF -#include -int main(void) { - unsigned a, b, c, d; - unsigned max = __get_cpuid_max(0, 0); - - if (max >= 1) { - __cpuid(1, a, b, c, d); - } - - if (max >= 7) { - __cpuid_count(7, 0, a, b, c, d); - } - - return 0; -} -EOF -if compile_prog "" "" ; then - cpuid_h=yes -fi - -########################################## -# avx2 optimization requirement check -# -# There is no point enabling this if cpuid.h is not usable, -# since we won't be able to select the new routines. - -if test "$cpuid_h" = "yes" && test "$avx2_opt" != "no"; then - cat > $TMPC << EOF -#pragma GCC push_options -#pragma GCC target("avx2") -#include -#include -static int bar(void *a) { - __m256i x = *(__m256i *)a; - return _mm256_testz_si256(x, x); -} -int main(int argc, char *argv[]) { return bar(argv[0]); } -EOF - if compile_object "-Werror" ; then - avx2_opt="yes" - else - avx2_opt="no" - fi -fi - -########################################## -# avx512f optimization requirement check -# -# There is no point enabling this if cpuid.h is not usable, -# since we won't be able to select the new routines. -# by default, it is turned off. -# if user explicitly want to enable it, check environment - -if test "$cpuid_h" = "yes" && test "$avx512f_opt" = "yes"; then - cat > $TMPC << EOF -#pragma GCC push_options -#pragma GCC target("avx512f") -#include -#include -static int bar(void *a) { - __m512i x = *(__m512i *)a; - return _mm512_test_epi64_mask(x, x); -} -int main(int argc, char *argv[]) -{ - return bar(argv[0]); -} -EOF - if ! compile_object "-Werror" ; then - avx512f_opt="no" - fi -else - avx512f_opt="no" -fi - ######################################## # check if __[u]int128_t is usable. @@ -2926,63 +2541,6 @@ if test "$fortify_source" != "no"; then fi fi -########################################## -# check for usable membarrier system call -if test "$membarrier" = "yes"; then - have_membarrier=no - if test "$mingw32" = "yes" ; then - have_membarrier=yes - elif test "$linux" = "yes" ; then - cat > $TMPC << EOF - #include - #include - #include - #include - int main(void) { - syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0); - syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0); - exit(0); - } -EOF - if compile_prog "" "" ; then - have_membarrier=yes - fi - fi - if test "$have_membarrier" = "no"; then - feature_not_found "membarrier" "membarrier system call not available" - fi -else - # Do not enable it by default even for Mingw32, because it doesn't - # work on Wine. - membarrier=no -fi - -########################################## -# check for usable AF_ALG environment -have_afalg=no -cat > $TMPC << EOF -#include -#include -#include -#include -int main(void) { - int sock; - sock = socket(AF_ALG, SOCK_SEQPACKET, 0); - return sock; -} -EOF -if compile_prog "" "" ; then - have_afalg=yes -fi -if test "$crypto_afalg" = "yes" -then - if test "$have_afalg" != "yes" - then - error_exit "AF_ALG requested but could not be detected" - fi -fi - - ########################################## # checks for sanitizers @@ -3064,19 +2622,6 @@ case "$slirp" in ;; esac -# Check for slirp smbd dupport -: ${smbd=${SMBD-/usr/sbin/smbd}} -if test "$slirp_smbd" != "no" ; then - if test "$mingw32" = "yes" ; then - if test "$slirp_smbd" = "yes" ; then - error_exit "Host smbd not supported on this platform." - fi - slirp_smbd=no - else - slirp_smbd=yes - fi -fi - ########################################## # check for usable __NR_keyctl syscall @@ -3132,11 +2677,6 @@ alpha) ;; esac -if test "$gprof" = "yes" ; then - QEMU_CFLAGS="-p $QEMU_CFLAGS" - QEMU_LDFLAGS="-p $QEMU_LDFLAGS" -fi - if test "$have_asan" = "yes"; then QEMU_CFLAGS="-fsanitize=address $QEMU_CFLAGS" QEMU_LDFLAGS="-fsanitize=address $QEMU_LDFLAGS" @@ -3188,20 +2728,6 @@ if test "$mingw32" = "yes" ; then done fi -# Probe for guest agent support/options - -if [ "$guest_agent" != "no" ]; then - if [ "$softmmu" = no -a "$want_tools" = no ] ; then - guest_agent=no - elif [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then - guest_agent=yes - elif [ "$guest_agent" != yes ]; then - guest_agent=no - else - error_exit "Guest agent is not supported on this platform" - fi -fi - # Guest agent Windows MSI package if test "$QEMU_GA_MANUFACTURER" = ""; then @@ -3302,14 +2828,6 @@ if test "$debug_tcg" = "yes" ; then fi if test "$mingw32" = "yes" ; then echo "CONFIG_WIN32=y" >> $config_host_mak - if test "$guest_agent_with_vss" = "yes" ; then - echo "CONFIG_QGA_VSS=y" >> $config_host_mak - echo "QGA_VSS_PROVIDER=$qga_vss_provider" >> $config_host_mak - echo "WIN_SDK=\"$win_sdk\"" >> $config_host_mak - fi - if test "$guest_agent_ntddscsi" = "yes" ; then - echo "CONFIG_QGA_NTDDSCSI=y" >> $config_host_mak - fi echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak echo "QEMU_GA_MANUFACTURER=${QEMU_GA_MANUFACTURER}" >> $config_host_mak echo "QEMU_GA_DISTRO=${QEMU_GA_DISTRO}" >> $config_host_mak @@ -3332,27 +2850,8 @@ fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=y" >> $config_host_mak fi -if test "$profiler" = "yes" ; then - echo "CONFIG_PROFILER=y" >> $config_host_mak -fi -if test "$want_tools" = "yes" ; then - echo "CONFIG_TOOLS=y" >> $config_host_mak -fi -if test "$guest_agent" = "yes" ; then - echo "CONFIG_GUEST_AGENT=y" >> $config_host_mak -fi -if test "$slirp_smbd" = "yes" ; then - echo "CONFIG_SLIRP_SMBD=y" >> $config_host_mak - echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak -fi -if test "$gprof" = "yes" ; then - echo "CONFIG_GPROF=y" >> $config_host_mak -fi echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak -if test "$block_drv_whitelist_tools" = "yes" ; then - echo "CONFIG_BDRV_WHITELIST_TOOLS=y" >> $config_host_mak -fi qemu_version=$(head $source_path/VERSION) echo "PKGVERSION=$pkgversion" >>$config_host_mak echo "SRC_PATH=$source_path" >> $config_host_mak @@ -3418,9 +2917,6 @@ fi if test "$vhost_user_fs" = "yes" ; then echo "CONFIG_VHOST_USER_FS=y" >> $config_host_mak fi -if test "$membarrier" = "yes" ; then - echo "CONFIG_MEMBARRIER=y" >> $config_host_mak -fi if test "$tcg" = "enabled" -a "$tcg_interpreter" = "true" ; then echo "CONFIG_TCG_INTERPRETER=y" >> $config_host_mak fi @@ -3431,37 +2927,12 @@ if test "$opengl" = "yes" ; then echo "OPENGL_LIBS=$opengl_libs" >> $config_host_mak fi -if test "$avx2_opt" = "yes" ; then - echo "CONFIG_AVX2_OPT=y" >> $config_host_mak -fi - -if test "$avx512f_opt" = "yes" ; then - echo "CONFIG_AVX512F_OPT=y" >> $config_host_mak -fi - # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak fi -if test "$qom_cast_debug" = "yes" ; then - echo "CONFIG_QOM_CAST_DEBUG=y" >> $config_host_mak -fi - echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak -if test "$coroutine_pool" = "yes" ; then - echo "CONFIG_COROUTINE_POOL=1" >> $config_host_mak -else - echo "CONFIG_COROUTINE_POOL=0" >> $config_host_mak -fi - -if test "$debug_stack_usage" = "yes" ; then - echo "CONFIG_DEBUG_STACK_USAGE=y" >> $config_host_mak -fi - -if test "$crypto_afalg" = "yes" ; then - echo "CONFIG_AF_ALG=y" >> $config_host_mak -fi if test "$have_asan_iface_fiber" = "yes" ; then echo "CONFIG_ASAN_IFACE_FIBER=y" >> $config_host_mak @@ -3471,10 +2942,6 @@ if test "$have_tsan" = "yes" && test "$have_tsan_iface_fiber" = "yes" ; then echo "CONFIG_TSAN=y" >> $config_host_mak fi -if test "$cpuid_h" = "yes" ; then - echo "CONFIG_CPUID_H=y" >> $config_host_mak -fi - if test "$int128" = "yes" ; then echo "CONFIG_INT128=y" >> $config_host_mak fi @@ -3487,14 +2954,6 @@ if test "$cmpxchg128" = "yes" ; then echo "CONFIG_CMPXCHG128=y" >> $config_host_mak fi -if test "$live_block_migration" = "yes" ; then - echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak -fi - -if test "$tpm" = "yes"; then - echo 'CONFIG_TPM=y' >> $config_host_mak -fi - if test "$rdma" = "yes" ; then echo "CONFIG_RDMA=y" >> $config_host_mak echo "RDMA_LIBS=$rdma_libs" >> $config_host_mak @@ -3504,39 +2963,6 @@ if test "$pvrdma" = "yes" ; then echo "CONFIG_PVRDMA=y" >> $config_host_mak fi -if test "$replication" = "yes" ; then - echo "CONFIG_REPLICATION=y" >> $config_host_mak -fi - -if test "$debug_mutex" = "yes" ; then - echo "CONFIG_DEBUG_MUTEX=y" >> $config_host_mak -fi - -if test "$bochs" = "yes" ; then - echo "CONFIG_BOCHS=y" >> $config_host_mak -fi -if test "$cloop" = "yes" ; then - echo "CONFIG_CLOOP=y" >> $config_host_mak -fi -if test "$dmg" = "yes" ; then - echo "CONFIG_DMG=y" >> $config_host_mak -fi -if test "$qcow1" = "yes" ; then - echo "CONFIG_QCOW1=y" >> $config_host_mak -fi -if test "$vdi" = "yes" ; then - echo "CONFIG_VDI=y" >> $config_host_mak -fi -if test "$vvfat" = "yes" ; then - echo "CONFIG_VVFAT=y" >> $config_host_mak -fi -if test "$qed" = "yes" ; then - echo "CONFIG_QED=y" >> $config_host_mak -fi -if test "$parallels" = "yes" ; then - echo "CONFIG_PARALLELS=y" >> $config_host_mak -fi - if test "$plugins" = "yes" ; then echo "CONFIG_PLUGIN=y" >> $config_host_mak fi @@ -3567,9 +2993,6 @@ echo "MESON=$meson" >> $config_host_mak echo "NINJA=$ninja" >> $config_host_mak echo "CC=$cc" >> $config_host_mak echo "HOST_CC=$host_cc" >> $config_host_mak -if $iasl -h > /dev/null 2>&1; then - echo "CONFIG_IASL=$iasl" >> $config_host_mak -fi echo "AR=$ar" >> $config_host_mak echo "AS=$as" >> $config_host_mak echo "CCAS=$ccas" >> $config_host_mak @@ -3586,11 +3009,6 @@ echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak echo "STRIP=$strip" >> $config_host_mak echo "EXESUF=$EXESUF" >> $config_host_mak -echo "LIBS_QGA=$libs_qga" >> $config_host_mak - -if test "$rng_none" = "yes"; then - echo "CONFIG_RNG_NONE=y" >> $config_host_mak -fi # use included Linux headers if test "$linux" = "yes" ; then @@ -3640,11 +3058,6 @@ if test "$default_targets" = "yes"; then echo "CONFIG_DEFAULT_TARGETS=y" >> $config_host_mak fi -if test "$numa" = "yes"; then - echo "CONFIG_NUMA=y" >> $config_host_mak - echo "NUMA_LIBS=$numa_libs" >> $config_host_mak -fi - if test "$ccache_cpp2" = "yes"; then echo "export CCACHE_CPP2=y" >> $config_host_mak fi @@ -3797,8 +3210,10 @@ if test "$skip_meson" = no; then -Daudio_drv_list=$audio_drv_list \ -Ddefault_devices=$default_devices \ -Ddocdir="$docdir" \ + -Diasl="$($iasl -h >/dev/null 2>&1 && printf %s "$iasl")" \ -Dqemu_firmwarepath="$firmwarepath" \ -Dqemu_suffix="$qemu_suffix" \ + -Dsmbd="$smbd" \ -Dsphinx_build="$sphinx_build" \ -Dtrace_file="$trace_file" \ -Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \ diff --git a/contrib/vhost-user-gpu/meson.build b/contrib/vhost-user-gpu/meson.build index 92c8f3a86a..c8883c2d8e 100644 --- a/contrib/vhost-user-gpu/meson.build +++ b/contrib/vhost-user-gpu/meson.build @@ -1,5 +1,4 @@ -if 'CONFIG_TOOLS' in config_host and virgl.found() and gbm.found() \ - and 'CONFIG_LINUX' in config_host and pixman.found() +if have_vhost_user_gpu executable('vhost-user-gpu', files('vhost-user-gpu.c', 'virgl.c', 'vugbm.c'), dependencies: [qemuutil, pixman, gbm, virgl, vhost_user, opengl], install: true, diff --git a/crypto/meson.build b/crypto/meson.build index 95a6a83504..19c44bea89 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -35,7 +35,9 @@ else endif crypto_ss.add(when: 'CONFIG_SECRET_KEYRING', if_true: files('secret_keyring.c')) -crypto_ss.add(when: 'CONFIG_AF_ALG', if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c')) +if have_afalg + crypto_ss.add(if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c')) +endif crypto_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c')) util_ss.add(files('aes.c')) @@ -48,7 +50,7 @@ if gcrypt.found() util_ss.add(gcrypt, files('random-gcrypt.c')) elif gnutls.found() util_ss.add(gnutls, files('random-gnutls.c')) -elif 'CONFIG_RNG_NONE' in config_host +elif get_option('rng_none') util_ss.add(files('random-none.c')) else util_ss.add(files('random-platform.c')) diff --git a/docs/devel/kconfig.rst b/docs/devel/kconfig.rst index a1cdbec751..69674d008a 100644 --- a/docs/devel/kconfig.rst +++ b/docs/devel/kconfig.rst @@ -192,11 +192,15 @@ declares its dependencies in different ways: no directive and are not used in the Makefile either; they only appear as conditions for ``default y`` directives. - QEMU currently has two device groups, ``PCI_DEVICES`` and - ``TEST_DEVICES``. PCI devices usually have a ``default y if + QEMU currently has three device groups, ``PCI_DEVICES``, ``I2C_DEVICES``, + and ``TEST_DEVICES``. PCI devices usually have a ``default y if PCI_DEVICES`` directive rather than just ``default y``. This lets some boards (notably s390) easily support a subset of PCI devices, for example only VFIO (passthrough) and virtio-pci devices. + ``I2C_DEVICES`` is similar to ``PCI_DEVICES``. It contains i2c devices + that users might reasonably want to plug in to an i2c bus on any + board (and not ones which are very board-specific or that need + to be wired up in a way that can't be done on the command line). ``TEST_DEVICES`` instead is used for devices that are rarely used on production virtual machines, but provide useful hooks to test QEMU or KVM. @@ -301,7 +305,7 @@ and also listed as follows in the top-level meson.build's host_kconfig variable:: host_kconfig = \ - ('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \ + (have_tpm ? ['CONFIG_TPM=y'] : []) + \ ('CONFIG_SPICE' in config_host ? ['CONFIG_SPICE=y'] : []) + \ (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \ ... diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json index 8d8b0be030..4e049b1c7c 100644 --- a/docs/interop/firmware.json +++ b/docs/interop/firmware.json @@ -210,24 +210,61 @@ 'data' : { 'filename' : 'str', 'format' : 'BlockdevDriver' } } + +## +# @FirmwareFlashType: +# +# Describes how the firmware build handles code versus variable +# persistence. +# +# @split: the executable file contains code while the NVRAM +# template provides variable storage. The executable +# must be configured read-only and can be shared between +# multiple guests. The NVRAM template must be cloned +# for each new guest and configured read-write. +# +# @combined: the executable file contains both code and +# variable storage. The executable must be cloned +# for each new guest and configured read-write. +# No NVRAM template will be specified. +# +# @stateless: the executable file contains code and variable +# storage is not persisted. The executable must +# be configured read-only and can be shared +# between multiple guests. No NVRAM template +# will be specified. +# +# Since: 7.0.0 +## +{ 'enum': 'FirmwareFlashMode', + 'data': [ 'split', 'combined', 'stateless' ] } + ## # @FirmwareMappingFlash: # # Describes loading and mapping properties for the firmware executable # and its accompanying NVRAM file, when @FirmwareDevice is @flash. # -# @executable: Identifies the firmware executable. The firmware -# executable may be shared by multiple virtual machine -# definitions. The preferred corresponding QEMU command -# line options are +# @mode: Describes how the firmware build handles code versus variable +# storage. If not present, it must be treated as if it was +# configured with value ``split``. Since: 7.0.0 +# +# @executable: Identifies the firmware executable. The @mode +# indicates whether there will be an associated +# NVRAM template present. The preferred +# corresponding QEMU command line options are # -drive if=none,id=pflash0,readonly=on,file=@executable.@filename,format=@executable.@format # -machine pflash0=pflash0 -# or equivalent -blockdev instead of -drive. +# or equivalent -blockdev instead of -drive. When +# @mode is ``combined`` the executable must be +# cloned before use and configured with readonly=off. # With QEMU versions older than 4.0, you have to use # -drive if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format # # @nvram-template: Identifies the NVRAM template compatible with -# @executable. Management software instantiates an +# @executable, when @mode is set to ``split``, +# otherwise it should not be present. +# Management software instantiates an # individual copy -- a specific NVRAM file -- from # @nvram-template.@filename for each new virtual # machine definition created. @nvram-template.@filename @@ -246,8 +283,9 @@ # Since: 3.0 ## { 'struct' : 'FirmwareMappingFlash', - 'data' : { 'executable' : 'FirmwareFlashFile', - 'nvram-template' : 'FirmwareFlashFile' } } + 'data' : { '*mode': 'FirmwareFlashMode', + 'executable' : 'FirmwareFlashFile', + '*nvram-template' : 'FirmwareFlashFile' } } ## # @FirmwareMappingKernel: diff --git a/docs/meson.build b/docs/meson.build index 57b28a3146..831d4aea2b 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -37,8 +37,6 @@ endif if build_docs SPHINX_ARGS += ['-Dversion=' + meson.project_version(), '-Drelease=' + config_host['PKGVERSION']] - have_ga = have_tools and config_host.has_key('CONFIG_GUEST_AGENT') - man_pages = { 'qemu-ga.8': (have_ga ? 'man8' : ''), 'qemu-ga-ref.7': (have_ga ? 'man7' : ''), diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst index adf497e679..ef2792076a 100644 --- a/docs/system/arm/nuvoton.rst +++ b/docs/system/arm/nuvoton.rst @@ -21,6 +21,7 @@ Hyperscale applications. The following machines are based on this chip : - ``quanta-gbs-bmc`` Quanta GBS server BMC - ``quanta-gsj`` Quanta GSJ server BMC - ``kudo-bmc`` Fii USA Kudo server BMC +- ``mori-bmc`` Fii USA Mori server BMC There are also two more SoCs, NPCM710 and NPCM705, which are single-core variants of NPCM750 and NPCM730, respectively. These are currently not diff --git a/docs/system/qemu-block-drivers.rst.inc b/docs/system/qemu-block-drivers.rst.inc index e313784426..dfe5d2293d 100644 --- a/docs/system/qemu-block-drivers.rst.inc +++ b/docs/system/qemu-block-drivers.rst.inc @@ -778,10 +778,32 @@ The optional *HOST_KEY_CHECK* parameter controls how the remote host's key is checked. The default is ``yes`` which means to use the local ``.ssh/known_hosts`` file. Setting this to ``no`` turns off known-hosts checking. Or you can check that the host key -matches a specific fingerprint: -``host_key_check=md5:78:45:8e:14:57:4f:d5:45:83:0a:0e:f3:49:82:c9:c8`` -(``sha1:`` can also be used as a prefix, but note that OpenSSH -tools only use MD5 to print fingerprints). +matches a specific fingerprint. The fingerprint can be provided in +``md5``, ``sha1``, or ``sha256`` format, however, it is strongly +recommended to only use ``sha256``, since the other options are +considered insecure by modern standards. The fingerprint value +must be given as a hex encoded string:: + + host_key_check=sha256:04ce2ae89ff4295a6b9c4111640bdcb3297858ee55cb434d9dd88796e93aa795 + +The key string may optionally contain ":" separators between +each pair of hex digits. + +The ``$HOME/.ssh/known_hosts`` file contains the base64 encoded +host keys. These can be converted into the format needed for +QEMU using a command such as:: + + $ for key in `grep 10.33.8.112 known_hosts | awk '{print $3}'` + do + echo $key | base64 -d | sha256sum + done + 6c3aa525beda9dc83eadfbd7e5ba7d976ecb59575d1633c87cd06ed2ed6e366f - + 12214fd9ea5b408086f98ecccd9958609bd9ac7c0ea316734006bc7818b45dc8 - + d36420137bcbd101209ef70c3b15dc07362fbe0fa53c5b135eba6e6afa82f0ce - + +Note that there can be multiple keys present per host, each with +different key ciphers. Care is needed to pick the key fingerprint +that matches the cipher QEMU will negotiate with the remote server. Currently authentication must be done using ssh-agent. Other authentication methods may be supported in future. diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst index 07ac0be551..0c0560203c 100644 --- a/docs/tools/virtiofsd.rst +++ b/docs/tools/virtiofsd.rst @@ -104,6 +104,13 @@ Options * posix_acl|no_posix_acl - Enable/disable posix acl support. Posix ACLs are disabled by default. + * security_label|no_security_label - + Enable/disable security label support. Security labels are disabled by + default. This will allow client to send a MAC label of file during + file creation. Typically this is expected to be SELinux security + label. Server will try to set that label on newly created file + atomically wherever possible. + .. option:: --socket-path=PATH Listen on vhost-user UNIX domain socket at PATH. @@ -348,6 +355,31 @@ client arguments or lists returned from the host. This stops the client seeing any 'security.' attributes on the server and stops it setting any. +SELinux support +--------------- +One can enable support for SELinux by running virtiofsd with option +"-o security_label". But this will try to save guest's security context +in xattr security.selinux on host and it might fail if host's SELinux +policy does not permit virtiofsd to do this operation. + +Hence, it is preferred to remap guest's "security.selinux" xattr to say +"trusted.virtiofs.security.selinux" on host. + +"-o xattrmap=:map:security.selinux:trusted.virtiofs.:" + +This will make sure that guest and host's SELinux xattrs on same file +remain separate and not interfere with each other. And will allow both +host and guest to implement their own separate SELinux policies. + +Setting trusted xattr on host requires CAP_SYS_ADMIN. So one will need +add this capability to daemon. + +"-o modcaps=+sys_admin" + +Giving CAP_SYS_ADMIN increases the risk on system. Now virtiofsd is more +powerful and if gets compromised, it can do lot of damage to host system. +So keep this trade-off in my mind while making a decision. + Examples -------- diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index b38088e066..7a7cd5c5ba 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -182,7 +182,12 @@ static int synth_opendir(FsContext *ctx, V9fsSynthOpenState *synth_open; V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; - synth_open = g_malloc(sizeof(*synth_open)); + /* + * V9fsSynthOpenState contains 'struct dirent' which have OS-specific + * properties, thus it's zero cleared on allocation here and below + * in synth_open. + */ + synth_open = g_new0(V9fsSynthOpenState, 1); synth_open->node = node; node->open_count++; fs->private = synth_open; @@ -220,7 +225,14 @@ static void synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) static void synth_direntry(V9fsSynthNode *node, struct dirent *entry, off_t off) { - strcpy(entry->d_name, node->name); + size_t sz = strlen(node->name) + 1; + /* + * 'entry' is always inside of V9fsSynthOpenState which have NAME_MAX + * back padding. Ensure we do not overflow it. + */ + g_assert(sizeof(struct dirent) + NAME_MAX >= + offsetof(struct dirent, d_name) + sz); + memcpy(entry->d_name, node->name, sz); entry->d_ino = node->attr->inode; entry->d_off = off + 1; } @@ -266,7 +278,7 @@ static int synth_open(FsContext *ctx, V9fsPath *fs_path, V9fsSynthOpenState *synth_open; V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; - synth_open = g_malloc(sizeof(*synth_open)); + synth_open = g_new0(V9fsSynthOpenState, 1); synth_open->node = node; node->open_count++; fs->private = synth_open; diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index 036d7e4a5b..eeb246f377 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -41,6 +41,11 @@ typedef struct V9fsSynthOpenState { off_t offset; V9fsSynthNode *node; struct dirent dent; + /* + * Ensure there is enough space for 'dent' above, some systems have a + * d_name size of just 1, which would cause a buffer overrun. + */ + char dent_trailing_space[NAME_MAX]; } V9fsSynthOpenState; int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 032cce04c4..c0873bde16 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -143,8 +143,7 @@ static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, } else { e = e->next = g_malloc0(sizeof(V9fsDirEnt)); } - e->dent = g_malloc0(sizeof(struct dirent)); - memcpy(e->dent, dent, sizeof(struct dirent)); + e->dent = qemu_dirent_dup(dent); /* perform a full stat() for directory entry if requested by caller */ if (dostat) { diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index a581a2183b..0a7e89a13e 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -1,6 +1,5 @@ #include "qemu/osdep.h" #include "hw/acpi/memory_hotplug.h" -#include "hw/acpi/pc-hotplug.h" #include "hw/mem/pc-dimm.h" #include "hw/qdev-core.h" #include "migration/vmstate.h" diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index f5b22983bb..8bea2e6933 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -25,7 +25,9 @@ acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c')) acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c')) acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c')) acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) -acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c')) +if have_tpm + acpi_ss.add(files('tpm.c')) +endif softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c')) softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c', diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 2e0049196d..6945330030 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -46,6 +46,7 @@ config DIGIC config EXYNOS4 bool + imply I2C_DEVICES select A9MPCORE select I2C select LAN9118 @@ -184,6 +185,7 @@ config REALVIEW bool imply PCI_DEVICES imply PCI_TESTDEV + imply I2C_DEVICES select SMC91C111 select LAN9118 select A9MPCORE @@ -229,6 +231,7 @@ config SABRELITE config STELLARIS bool + imply I2C_DEVICES select ARM_V7M select CMSDK_APB_WATCHDOG select I2C @@ -406,6 +409,7 @@ config NPCM7XX config FSL_IMX25 bool + imply I2C_DEVICES select IMX select IMX_FEC select IMX_I2C @@ -414,6 +418,7 @@ config FSL_IMX25 config FSL_IMX31 bool + imply I2C_DEVICES select SERIAL select IMX select IMX_I2C @@ -422,6 +427,7 @@ config FSL_IMX31 config FSL_IMX6 bool + imply I2C_DEVICES select A9MPCORE select IMX select IMX_FEC @@ -450,6 +456,7 @@ config ASPEED_SOC config MPS2 bool + imply I2C_DEVICES select ARMSSE select LAN9118 select MPS2_FPGAIO @@ -466,6 +473,7 @@ config FSL_IMX7 bool imply PCI_DEVICES imply TEST_DEVICES + imply I2C_DEVICES select A15MPCORE select PCI select IMX @@ -481,6 +489,7 @@ config ARM_SMMUV3 config FSL_IMX6UL bool + imply I2C_DEVICES select A15MPCORE select IMX select IMX_FEC @@ -495,6 +504,7 @@ config MICROBIT config NRF51_SOC bool + imply I2C_DEVICES select I2C select ARM_V7M select UNIMP diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index ceb76df3cd..41cfca0f22 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -284,6 +284,12 @@ static void armv7m_realize(DeviceState *dev, Error **errp) return; } + /* cpuclk must be connected; refclk is optional */ + if (!clock_has_source(s->cpuclk)) { + error_setg(errp, "armv7m: cpuclk must be connected"); + return; + } + memory_region_add_subregion_overlap(&s->container, 0, s->board_memory, -1); s->cpu = ARM_CPU(object_new_with_props(s->cpu_type, OBJECT(s), "cpu", @@ -420,8 +426,18 @@ static void armv7m_realize(DeviceState *dev, Error **errp) &s->sysreg_ns_mem); } - /* Create and map the systick devices */ - qdev_connect_clock_in(DEVICE(&s->systick[M_REG_NS]), "refclk", s->refclk); + /* + * Create and map the systick devices. Note that we only connect + * refclk if it has been connected to us; otherwise the systick + * device gets the wrong answer for clock_has_source(refclk), because + * it has an immediate source (the ARMv7M's clock object) but not + * an ultimate source, and then it won't correctly auto-select the + * CPU clock as its only possible clock source. + */ + if (clock_has_source(s->refclk)) { + qdev_connect_clock_in(DEVICE(&s->systick[M_REG_NS]), "refclk", + s->refclk); + } qdev_connect_clock_in(DEVICE(&s->systick[M_REG_NS]), "cpuclk", s->cpuclk); if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), errp)) { return; @@ -438,8 +454,10 @@ static void armv7m_realize(DeviceState *dev, Error **errp) */ object_initialize_child(OBJECT(dev), "systick-reg-s", &s->systick[M_REG_S], TYPE_SYSTICK); - qdev_connect_clock_in(DEVICE(&s->systick[M_REG_S]), "refclk", - s->refclk); + if (clock_has_source(s->refclk)) { + qdev_connect_clock_in(DEVICE(&s->systick[M_REG_S]), "refclk", + s->refclk); + } qdev_connect_clock_in(DEVICE(&s->systick[M_REG_S]), "cpuclk", s->cpuclk); diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index d701e5cc55..0678a56156 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -34,6 +34,7 @@ #define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff #define QUANTA_GBS_POWER_ON_STRAPS 0x000017ff #define KUDO_BMC_POWER_ON_STRAPS 0x00001fff +#define MORI_BMC_POWER_ON_STRAPS 0x00001fff static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin"; @@ -429,6 +430,21 @@ static void kudo_bmc_init(MachineState *machine) npcm7xx_load_kernel(machine, soc); } +static void mori_bmc_init(MachineState *machine) +{ + NPCM7xxState *soc; + + soc = npcm7xx_create_soc(machine, MORI_BMC_POWER_ON_STRAPS); + npcm7xx_connect_dram(soc, machine->ram); + qdev_realize(DEVICE(soc), NULL, &error_fatal); + + npcm7xx_load_bootrom(machine, soc); + npcm7xx_connect_flash(&soc->fiu[1], 0, "mx66u51235f", + drive_get(IF_MTD, 3, 0)); + + npcm7xx_load_kernel(machine, soc); +} + static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type) { NPCM7xxClass *sc = NPCM7XX_CLASS(object_class_by_name(type)); @@ -501,6 +517,18 @@ static void kudo_bmc_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 1 * GiB; }; +static void mori_bmc_machine_class_init(ObjectClass *oc, void *data) +{ + NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); + MachineClass *mc = MACHINE_CLASS(oc); + + npcm7xx_set_soc_type(nmc, TYPE_NPCM730); + + mc->desc = "Mori BMC (Cortex-A9)"; + mc->init = mori_bmc_init; + mc->default_ram_size = 1 * GiB; +} + static const TypeInfo npcm7xx_machine_types[] = { { .name = TYPE_NPCM7XX_MACHINE, @@ -525,6 +553,10 @@ static const TypeInfo npcm7xx_machine_types[] = { .name = MACHINE_TYPE_NAME("kudo-bmc"), .parent = TYPE_NPCM7XX_MACHINE, .class_init = kudo_bmc_machine_class_init, + }, { + .name = MACHINE_TYPE_NAME("mori-bmc"), + .parent = TYPE_NPCM7XX_MACHINE, + .class_init = mori_bmc_machine_class_init, }, }; diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index af3164c551..9c1cafae86 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -24,6 +24,7 @@ #include "chardev/char.h" #include "qemu/cutils.h" #include "qemu/bswap.h" +#include "qemu/hw-version.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 9852c2a07e..f693faa43e 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qapi/error.h" diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index 504ed7ca72..c666545aa0 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -207,7 +207,7 @@ static void generic_loader_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); } -static TypeInfo generic_loader_info = { +static const TypeInfo generic_loader_info = { .name = TYPE_GENERIC_LOADER, .parent = TYPE_DEVICE, .instance_size = sizeof(GenericLoaderState), diff --git a/hw/core/guest-loader.c b/hw/core/guest-loader.c index d3f9d1a06e..391c875a29 100644 --- a/hw/core/guest-loader.c +++ b/hw/core/guest-loader.c @@ -129,7 +129,7 @@ static void guest_loader_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); } -static TypeInfo guest_loader_info = { +static const TypeInfo guest_loader_info = { .name = TYPE_GUEST_LOADER, .parent = TYPE_DEVICE, .instance_size = sizeof(GuestLoaderState), diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 6ba19fd965..eb5ba1aff7 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -14,7 +14,6 @@ #include "sysemu/cpu-timers.h" #include "sysemu/qtest.h" #include "block/aio.h" -#include "sysemu/cpus.h" #include "hw/clock.h" #define DELTA_ADJUST 1 diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index 2be77bdd3a..088fc3d51c 100644 --- a/hw/display/bcm2835_fb.c +++ b/hw/display/bcm2835_fb.c @@ -454,7 +454,7 @@ static void bcm2835_fb_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_fb; } -static TypeInfo bcm2835_fb_info = { +static const TypeInfo bcm2835_fb_info = { .name = TYPE_BCM2835_FB, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835FBState), diff --git a/hw/display/i2c-ddc.c b/hw/display/i2c-ddc.c index 13eb529fc1..146489518c 100644 --- a/hw/display/i2c-ddc.c +++ b/hw/display/i2c-ddc.c @@ -113,7 +113,7 @@ static void i2c_ddc_class_init(ObjectClass *oc, void *data) isc->send = i2c_ddc_tx; } -static TypeInfo i2c_ddc_info = { +static const TypeInfo i2c_ddc_info = { .name = TYPE_I2CDDC, .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(I2CDDCState), diff --git a/hw/display/macfb.c b/hw/display/macfb.c index 2eeb80cc3f..c9b468c10e 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -782,14 +782,14 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, macfb_nubus_properties); } -static TypeInfo macfb_sysbus_info = { +static const TypeInfo macfb_sysbus_info = { .name = TYPE_MACFB, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MacfbSysBusState), .class_init = macfb_sysbus_class_init, }; -static TypeInfo macfb_nubus_info = { +static const TypeInfo macfb_nubus_info = { .name = TYPE_NUBUS_MACFB, .parent = TYPE_NUBUS_DEVICE, .instance_size = sizeof(MacfbNubusState), diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c index 21fde58a26..8c0e9ee700 100644 --- a/hw/display/omap_dss.c +++ b/hw/display/omap_dss.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/hw.h" #include "hw/irq.h" #include "ui/console.h" diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index b23a75a04b..5a2f7a4540 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -220,7 +220,7 @@ static void virtio_vga_base_class_init(ObjectClass *klass, void *data) virtio_vga_set_big_endian_fb); } -static TypeInfo virtio_vga_base_info = { +static const TypeInfo virtio_vga_base_info = { .name = TYPE_VIRTIO_VGA_BASE, .parent = TYPE_VIRTIO_PCI, .instance_size = sizeof(VirtIOVGABase), diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c index eb0002a2b9..5e9306110d 100644 --- a/hw/dma/bcm2835_dma.c +++ b/hw/dma/bcm2835_dma.c @@ -394,7 +394,7 @@ static void bcm2835_dma_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_dma; } -static TypeInfo bcm2835_dma_info = { +static const TypeInfo bcm2835_dma_info = { .name = TYPE_BCM2835_DMA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835DMAState), diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c index e25084b40c..bd0841d57f 100644 --- a/hw/gpio/omap_gpio.c +++ b/hw/gpio/omap_gpio.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/arm/omap.h" diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 8217cb5041..9bb8870517 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -1,6 +1,11 @@ config I2C bool +config I2C_DEVICES + # Device group for i2c devices which can reasonably be user-plugged + # to any board's i2c bus + bool + config SMBUS bool select I2C diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index d9b344248d..8d33cf689d 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -867,7 +867,7 @@ static void isa_bridge_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_ISA; }; -static TypeInfo isa_bridge_info = { +static const TypeInfo isa_bridge_info = { .name = "igd-passthrough-isa-bridge", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c index 96b2940d75..d664829d35 100644 --- a/hw/i386/sgx-epc.c +++ b/hw/i386/sgx-epc.c @@ -167,7 +167,7 @@ static void sgx_epc_class_init(ObjectClass *oc, void *data) mdc->fill_device_info = sgx_epc_md_fill_device_info; } -static TypeInfo sgx_epc_info = { +static const TypeInfo sgx_epc_info = { .name = TYPE_SGX_EPC, .parent = TYPE_DEVICE, .instance_size = sizeof(SGXEPCDevice), diff --git a/hw/ide/core.c b/hw/ide/core.c index e28f8aad61..33463d9b8f 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/timer.h" +#include "qemu/hw-version.h" #include "sysemu/sysemu.h" #include "sysemu/blockdev.h" #include "sysemu/dma.h" diff --git a/hw/input/hid.c b/hw/input/hid.c index 8aab0521f4..e7ecebdf8f 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -114,6 +114,8 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src, [INPUT_BUTTON_LEFT] = 0x01, [INPUT_BUTTON_RIGHT] = 0x02, [INPUT_BUTTON_MIDDLE] = 0x04, + [INPUT_BUTTON_SIDE] = 0x08, + [INPUT_BUTTON_EXTRA] = 0x10, }; HIDState *hs = (HIDState *)dev; HIDPointerEvent *e; diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index 182d3725fc..b0d5c2dd74 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -20,6 +20,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/hw.h" #include "audio/audio.h" #include "qemu/timer.h" diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c index 9000d995e8..4513fad16f 100644 --- a/hw/intc/bcm2835_ic.c +++ b/hw/intc/bcm2835_ic.c @@ -227,7 +227,7 @@ static void bcm2835_ic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_ic; } -static TypeInfo bcm2835_ic_info = { +static const TypeInfo bcm2835_ic_info = { .name = TYPE_BCM2835_IC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835ICState), diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c index 2ead76ffdc..b0589df188 100644 --- a/hw/intc/bcm2836_control.c +++ b/hw/intc/bcm2836_control.c @@ -392,7 +392,7 @@ static void bcm2836_control_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2836_control; } -static TypeInfo bcm2836_control_info = { +static const TypeInfo bcm2836_control_info = { .name = TYPE_BCM2836_CONTROL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2836ControlState), diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c index 8d35c9fdd6..bbb07b151e 100644 --- a/hw/ipmi/ipmi.c +++ b/hw/ipmi/ipmi.c @@ -85,7 +85,7 @@ static void ipmi_interface_class_init(ObjectClass *class, void *data) ik->do_hw_op = ipmi_do_hw_op; } -static TypeInfo ipmi_interface_type_info = { +static const TypeInfo ipmi_interface_type_info = { .name = TYPE_IPMI_INTERFACE, .parent = TYPE_INTERFACE, .class_size = sizeof(IPMIInterfaceClass), @@ -120,7 +120,7 @@ static void bmc_class_init(ObjectClass *oc, void *data) device_class_set_props(dc, ipmi_bmc_properties); } -static TypeInfo ipmi_bmc_type_info = { +static const TypeInfo ipmi_bmc_type_info = { .name = TYPE_IPMI_BMC, .parent = TYPE_DEVICE, .instance_size = sizeof(IPMIBmc), diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 7397b67156..7c7d777781 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -181,10 +181,25 @@ static MemoryRegion *nvdimm_md_get_memory_region(MemoryDeviceState *md, static void nvdimm_realize(PCDIMMDevice *dimm, Error **errp) { NVDIMMDevice *nvdimm = NVDIMM(dimm); + NVDIMMClass *ndc = NVDIMM_GET_CLASS(nvdimm); if (!nvdimm->nvdimm_mr) { nvdimm_prepare_memory_region(nvdimm, errp); } + + if (ndc->realize) { + ndc->realize(nvdimm, errp); + } +} + +static void nvdimm_unrealize(PCDIMMDevice *dimm) +{ + NVDIMMDevice *nvdimm = NVDIMM(dimm); + NVDIMMClass *ndc = NVDIMM_GET_CLASS(nvdimm); + + if (ndc->unrealize) { + ndc->unrealize(nvdimm); + } } /* @@ -240,6 +255,7 @@ static void nvdimm_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); ddc->realize = nvdimm_realize; + ddc->unrealize = nvdimm_unrealize; mdc->get_memory_region = nvdimm_md_get_memory_region; device_class_set_props(dc, nvdimm_properties); @@ -248,7 +264,7 @@ static void nvdimm_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } -static TypeInfo nvdimm_info = { +static const TypeInfo nvdimm_info = { .name = TYPE_NVDIMM, .parent = TYPE_PC_DIMM, .class_size = sizeof(NVDIMMClass), diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 48b913aba6..f27e1a11ba 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -216,6 +216,11 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp) static void pc_dimm_unrealize(DeviceState *dev) { PCDIMMDevice *dimm = PC_DIMM(dev); + PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); + + if (ddc->unrealize) { + ddc->unrealize(dimm); + } host_memory_backend_set_mapped(dimm->hostmem, false); } @@ -286,7 +291,7 @@ static void pc_dimm_class_init(ObjectClass *oc, void *data) mdc->fill_device_info = pc_dimm_md_fill_device_info; } -static TypeInfo pc_dimm_info = { +static const TypeInfo pc_dimm_info = { .name = TYPE_PC_DIMM, .parent = TYPE_DEVICE, .instance_size = sizeof(PCDIMMDevice), diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c index 04e53c9828..1e4e061bc1 100644 --- a/hw/misc/bcm2835_mbox.c +++ b/hw/misc/bcm2835_mbox.c @@ -323,7 +323,7 @@ static void bcm2835_mbox_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_mbox; } -static TypeInfo bcm2835_mbox_info = { +static const TypeInfo bcm2835_mbox_info = { .name = TYPE_BCM2835_MBOX, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835MboxState), diff --git a/hw/misc/bcm2835_powermgt.c b/hw/misc/bcm2835_powermgt.c index 25fa804cbd..976f3d34e5 100644 --- a/hw/misc/bcm2835_powermgt.c +++ b/hw/misc/bcm2835_powermgt.c @@ -144,7 +144,7 @@ static void bcm2835_powermgt_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_powermgt; } -static TypeInfo bcm2835_powermgt_info = { +static const TypeInfo bcm2835_powermgt_info = { .name = TYPE_BCM2835_POWERMGT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835PowerMgtState), diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 76ea511d53..e94e951057 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -421,7 +421,7 @@ static void bcm2835_property_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_property; } -static TypeInfo bcm2835_property_info = { +static const TypeInfo bcm2835_property_info = { .name = TYPE_BCM2835_PROPERTY, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835PropertyState), diff --git a/hw/misc/bcm2835_rng.c b/hw/misc/bcm2835_rng.c index d0c4e64e88..b3c80cf186 100644 --- a/hw/misc/bcm2835_rng.c +++ b/hw/misc/bcm2835_rng.c @@ -131,7 +131,7 @@ static void bcm2835_rng_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_rng; } -static TypeInfo bcm2835_rng_info = { +static const TypeInfo bcm2835_rng_info = { .name = TYPE_BCM2835_RNG, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835RngState), diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c index 7b66d58acc..a39fcdd1fc 100644 --- a/hw/misc/pvpanic-isa.c +++ b/hw/misc/pvpanic-isa.c @@ -77,7 +77,7 @@ static void pvpanic_isa_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); } -static TypeInfo pvpanic_isa_info = { +static const TypeInfo pvpanic_isa_info = { .name = TYPE_PVPANIC_ISA_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PVPanicISAState), diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c index af8cbe2830..62e1be68c1 100644 --- a/hw/misc/pvpanic-pci.c +++ b/hw/misc/pvpanic-pci.c @@ -74,7 +74,7 @@ static void pvpanic_pci_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); } -static TypeInfo pvpanic_pci_info = { +static const TypeInfo pvpanic_pci_info = { .name = TYPE_PVPANIC_PCI_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PVPanicPCIState), diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index bd9d62b559..e7fc082518 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -430,7 +430,7 @@ static void etsec_class_init(ObjectClass *klass, void *data) dc->user_creatable = true; } -static TypeInfo etsec_info = { +static const TypeInfo etsec_info = { .name = TYPE_ETSEC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(eTSEC), diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index af6f5dbb99..da435500ba 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -54,7 +54,7 @@ struct EEPROMState { static int at24c_eeprom_event(I2CSlave *s, enum i2c_event event) { - EEPROMState *ee = container_of(s, EEPROMState, parent_obj); + EEPROMState *ee = AT24C_EE(s); switch (event) { case I2C_START_SEND: diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 298e6b93e2..d45008ac71 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -449,6 +449,11 @@ static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *pm, } } +static bool pegasos2_cpu_in_nested(PowerPCCPU *cpu) +{ + return false; +} + static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) { Pegasos2MachineState *pm = PEGASOS2_MACHINE(vhyp); @@ -504,6 +509,7 @@ static void pegasos2_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_id = "pegasos2.ram"; mc->default_ram_size = 512 * MiB; + vhc->cpu_in_nested = pegasos2_cpu_in_nested; vhc->hypercall = pegasos2_hypercall; vhc->cpu_exec_enter = vhyp_nop; vhc->cpu_exec_exit = vhyp_nop; diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index ba7fa0f3b5..9e99625ea9 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -1072,7 +1072,7 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) } /* Create new timer */ tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); - if (env->has_hv_mode) { + if (env->has_hv_mode && !cpu->vhyp) { tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, cpu); } else { @@ -1083,6 +1083,27 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) return &cpu_ppc_set_tb_clk; } +/* cpu_ppc_hdecr_init may be used if the timer is not used by HDEC emulation */ +void cpu_ppc_hdecr_init(CPUPPCState *env) +{ + PowerPCCPU *cpu = env_archcpu(env); + + assert(env->tb_env->hdecr_timer == NULL); + + env->tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + &cpu_ppc_hdecr_cb, cpu); +} + +void cpu_ppc_hdecr_exit(CPUPPCState *env) +{ + PowerPCCPU *cpu = env_archcpu(env); + + timer_free(env->tb_env->hdecr_timer); + env->tb_env->hdecr_timer = NULL; + + cpu_ppc_hdecr_lower(cpu); +} + /*****************************************************************************/ /* PowerPC 40x timers */ diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c index b2bd783248..8c9b8dd67b 100644 --- a/hw/ppc/prep_systemio.c +++ b/hw/ppc/prep_systemio.c @@ -300,7 +300,7 @@ static void prep_systemio_class_initfn(ObjectClass *klass, void *data) device_class_set_props(dc, prep_systemio_properties); } -static TypeInfo prep_systemio800_info = { +static const TypeInfo prep_systemio800_info = { .name = TYPE_PREP_SYSTEMIO, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PrepSystemIoState), diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 3d6ec309dd..f0b75b22bb 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1270,6 +1270,8 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, /* The TCG path should also be holding the BQL at this point */ g_assert(qemu_mutex_iothread_locked()); + g_assert(!vhyp_cpu_in_nested(cpu)); + if (msr_pr) { hcall_dprintf("Hypercall made with MSR[PR]=1\n"); env->gpr[3] = H_PRIVILEGE; @@ -1309,13 +1311,40 @@ void spapr_set_all_lpcrs(target_ulong value, target_ulong mask) } } -static void spapr_get_pate(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry) +static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu, + target_ulong lpid, ppc_v3_pate_t *entry) { SpaprMachineState *spapr = SPAPR_MACHINE(vhyp); + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - /* Copy PATE1:GR into PATE0:HR */ - entry->dw0 = spapr->patb_entry & PATE0_HR; - entry->dw1 = spapr->patb_entry; + if (!spapr_cpu->in_nested) { + assert(lpid == 0); + + /* Copy PATE1:GR into PATE0:HR */ + entry->dw0 = spapr->patb_entry & PATE0_HR; + entry->dw1 = spapr->patb_entry; + + } else { + uint64_t patb, pats; + + assert(lpid != 0); + + patb = spapr->nested_ptcr & PTCR_PATB; + pats = spapr->nested_ptcr & PTCR_PATS; + + /* Calculate number of entries */ + pats = 1ull << (pats + 12 - 4); + if (pats <= lpid) { + return false; + } + + /* Grab entry */ + patb += 16 * lpid; + entry->dw0 = ldq_phys(CPU(cpu)->as, patb); + entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8); + } + + return true; } #define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2)) @@ -1634,6 +1663,8 @@ static void spapr_machine_reset(MachineState *machine) spapr->ov5_cas = spapr_ovec_clone(spapr->ov5); } + spapr_nvdimm_finish_flushes(); + /* DRC reset may cause a device to be unplugged. This will cause troubles * if this device is used by another device (eg, a running vhost backend * will crash QEMU if the DIMM holding the vring goes away). To avoid such @@ -4465,6 +4496,13 @@ PowerPCCPU *spapr_find_cpu(int vcpu_id) return NULL; } +static bool spapr_cpu_in_nested(PowerPCCPU *cpu) +{ + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + + return spapr_cpu->in_nested; +} + static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) { SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); @@ -4573,6 +4611,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; smc->phb_placement = spapr_phb_placement; + vhc->cpu_in_nested = spapr_cpu_in_nested; + vhc->deliver_hv_excp = spapr_exit_nested; vhc->hypercall = emulate_spapr_hypercall; vhc->hpt_mask = spapr_hpt_mask; vhc->map_hptes = spapr_map_hptes; diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index ed7c077a0d..6167431271 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -444,19 +444,23 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, { ERRP_GUARD(); PowerPCCPU *cpu = POWERPC_CPU(first_cpu); + CPUPPCState *env = &cpu->env; if (!val) { /* capability disabled by default */ return; } - if (tcg_enabled()) { - error_setg(errp, "No Nested KVM-HV support in TCG"); + if (!(env->insns_flags2 & PPC2_ISA300)) { + error_setg(errp, "Nested-HV only supported on POWER9 and later"); error_append_hint(errp, "Try appending -machine cap-nested-hv=off\n"); - } else if (kvm_enabled()) { + return; + } + + if (kvm_enabled()) { if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { - error_setg(errp, "Nested KVM-HV only supported on POWER9"); + error_setg(errp, "Nested-HV only supported on POWER9 and later"); error_append_hint(errp, "Try appending -machine max-cpu-compat=power9\n"); return; @@ -464,7 +468,7 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, if (!kvmppc_has_cap_nested_kvm_hv()) { error_setg(errp, - "KVM implementation does not support Nested KVM-HV"); + "KVM implementation does not support Nested-HV"); error_append_hint(errp, "Try appending -machine cap-nested-hv=off\n"); } else if (kvmppc_set_cap_nested_kvm_hv(val) < 0) { diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index a781e97f8d..ed84713960 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -261,12 +261,12 @@ static bool spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, return false; } - /* Set time-base frequency to 512 MHz */ - cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); - cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); kvmppc_set_papr(cpu); + /* Set time-base frequency to 512 MHz. vhyp must be set first. */ + cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); + if (spapr_irq_cpu_intc_create(spapr, cpu, errp) < 0) { qdev_unrealize(DEVICE(cpu)); return false; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 222c1b6bbd..f008290787 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -9,6 +9,7 @@ #include "qemu/error-report.h" #include "exec/exec-all.h" #include "helper_regs.h" +#include "hw/ppc/ppc.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_cpu_core.h" #include "mmu-hash64.h" @@ -1497,6 +1498,333 @@ static void hypercall_register_softmmu(void) } #endif +/* TCG only */ +#define PRTS_MASK 0x1f + +static target_ulong h_set_ptbl(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong ptcr = args[0]; + + if (!spapr_get_cap(spapr, SPAPR_CAP_NESTED_KVM_HV)) { + return H_FUNCTION; + } + + if ((ptcr & PRTS_MASK) + 12 - 4 > 12) { + return H_PARAMETER; + } + + spapr->nested_ptcr = ptcr; /* Save new partition table */ + + return H_SUCCESS; +} + +static target_ulong h_tlb_invalidate(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + /* + * The spapr virtual hypervisor nested HV implementation retains no L2 + * translation state except for TLB. And the TLB is always invalidated + * across L1<->L2 transitions, so nothing is required here. + */ + + return H_SUCCESS; +} + +static target_ulong h_copy_tofrom_guest(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + /* + * This HCALL is not required, L1 KVM will take a slow path and walk the + * page tables manually to do the data copy. + */ + return H_FUNCTION; +} + +/* + * When this handler returns, the environment is switched to the L2 guest + * and TCG begins running that. spapr_exit_nested() performs the switch from + * L2 back to L1 and returns from the H_ENTER_NESTED hcall. + */ +static target_ulong h_enter_nested(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + target_ulong hv_ptr = args[0]; + target_ulong regs_ptr = args[1]; + target_ulong hdec, now = cpu_ppc_load_tbl(env); + target_ulong lpcr, lpcr_mask; + struct kvmppc_hv_guest_state *hvstate; + struct kvmppc_hv_guest_state hv_state; + struct kvmppc_pt_regs *regs; + hwaddr len; + uint64_t cr; + int i; + + if (spapr->nested_ptcr == 0) { + return H_NOT_AVAILABLE; + } + + len = sizeof(*hvstate); + hvstate = address_space_map(CPU(cpu)->as, hv_ptr, &len, false, + MEMTXATTRS_UNSPECIFIED); + if (len != sizeof(*hvstate)) { + address_space_unmap(CPU(cpu)->as, hvstate, len, 0, false); + return H_PARAMETER; + } + + memcpy(&hv_state, hvstate, len); + + address_space_unmap(CPU(cpu)->as, hvstate, len, len, false); + + /* + * We accept versions 1 and 2. Version 2 fields are unused because TCG + * does not implement DAWR*. + */ + if (hv_state.version > HV_GUEST_STATE_VERSION) { + return H_PARAMETER; + } + + spapr_cpu->nested_host_state = g_try_malloc(sizeof(CPUPPCState)); + if (!spapr_cpu->nested_host_state) { + return H_NO_MEM; + } + + memcpy(spapr_cpu->nested_host_state, env, sizeof(CPUPPCState)); + + len = sizeof(*regs); + regs = address_space_map(CPU(cpu)->as, regs_ptr, &len, false, + MEMTXATTRS_UNSPECIFIED); + if (!regs || len != sizeof(*regs)) { + address_space_unmap(CPU(cpu)->as, regs, len, 0, false); + g_free(spapr_cpu->nested_host_state); + return H_P2; + } + + len = sizeof(env->gpr); + assert(len == sizeof(regs->gpr)); + memcpy(env->gpr, regs->gpr, len); + + env->lr = regs->link; + env->ctr = regs->ctr; + cpu_write_xer(env, regs->xer); + + cr = regs->ccr; + for (i = 7; i >= 0; i--) { + env->crf[i] = cr & 15; + cr >>= 4; + } + + env->msr = regs->msr; + env->nip = regs->nip; + + address_space_unmap(CPU(cpu)->as, regs, len, len, false); + + env->cfar = hv_state.cfar; + + assert(env->spr[SPR_LPIDR] == 0); + env->spr[SPR_LPIDR] = hv_state.lpid; + + lpcr_mask = LPCR_DPFD | LPCR_ILE | LPCR_AIL | LPCR_LD | LPCR_MER; + lpcr = (env->spr[SPR_LPCR] & ~lpcr_mask) | (hv_state.lpcr & lpcr_mask); + lpcr |= LPCR_HR | LPCR_UPRT | LPCR_GTSE | LPCR_HVICE | LPCR_HDICE; + lpcr &= ~LPCR_LPES0; + env->spr[SPR_LPCR] = lpcr & pcc->lpcr_mask; + + env->spr[SPR_PCR] = hv_state.pcr; + /* hv_state.amor is not used */ + env->spr[SPR_DPDES] = hv_state.dpdes; + env->spr[SPR_HFSCR] = hv_state.hfscr; + hdec = hv_state.hdec_expiry - now; + spapr_cpu->nested_tb_offset = hv_state.tb_offset; + /* TCG does not implement DAWR*, CIABR, PURR, SPURR, IC, VTB, HEIR SPRs*/ + env->spr[SPR_SRR0] = hv_state.srr0; + env->spr[SPR_SRR1] = hv_state.srr1; + env->spr[SPR_SPRG0] = hv_state.sprg[0]; + env->spr[SPR_SPRG1] = hv_state.sprg[1]; + env->spr[SPR_SPRG2] = hv_state.sprg[2]; + env->spr[SPR_SPRG3] = hv_state.sprg[3]; + env->spr[SPR_BOOKS_PID] = hv_state.pidr; + env->spr[SPR_PPR] = hv_state.ppr; + + cpu_ppc_hdecr_init(env); + cpu_ppc_store_hdecr(env, hdec); + + /* + * The hv_state.vcpu_token is not needed. It is used by the KVM + * implementation to remember which L2 vCPU last ran on which physical + * CPU so as to invalidate process scope translations if it is moved + * between physical CPUs. For now TLBs are always flushed on L1<->L2 + * transitions so this is not a problem. + * + * Could validate that the same vcpu_token does not attempt to run on + * different L1 vCPUs at the same time, but that would be a L1 KVM bug + * and it's not obviously worth a new data structure to do it. + */ + + env->tb_env->tb_offset += spapr_cpu->nested_tb_offset; + spapr_cpu->in_nested = true; + + hreg_compute_hflags(env); + tlb_flush(cs); + env->reserve_addr = -1; /* Reset the reservation */ + + /* + * The spapr hcall helper sets env->gpr[3] to the return value, but at + * this point the L1 is not returning from the hcall but rather we + * start running the L2, so r3 must not be clobbered, so return env->gpr[3] + * to leave it unchanged. + */ + return env->gpr[3]; +} + +void spapr_exit_nested(PowerPCCPU *cpu, int excp) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + target_ulong r3_return = env->excp_vectors[excp]; /* hcall return value */ + target_ulong hv_ptr = spapr_cpu->nested_host_state->gpr[4]; + target_ulong regs_ptr = spapr_cpu->nested_host_state->gpr[5]; + struct kvmppc_hv_guest_state *hvstate; + struct kvmppc_pt_regs *regs; + hwaddr len; + uint64_t cr; + int i; + + assert(spapr_cpu->in_nested); + + cpu_ppc_hdecr_exit(env); + + len = sizeof(*hvstate); + hvstate = address_space_map(CPU(cpu)->as, hv_ptr, &len, true, + MEMTXATTRS_UNSPECIFIED); + if (len != sizeof(*hvstate)) { + address_space_unmap(CPU(cpu)->as, hvstate, len, 0, true); + r3_return = H_PARAMETER; + goto out_restore_l1; + } + + hvstate->cfar = env->cfar; + hvstate->lpcr = env->spr[SPR_LPCR]; + hvstate->pcr = env->spr[SPR_PCR]; + hvstate->dpdes = env->spr[SPR_DPDES]; + hvstate->hfscr = env->spr[SPR_HFSCR]; + + if (excp == POWERPC_EXCP_HDSI) { + hvstate->hdar = env->spr[SPR_HDAR]; + hvstate->hdsisr = env->spr[SPR_HDSISR]; + hvstate->asdr = env->spr[SPR_ASDR]; + } else if (excp == POWERPC_EXCP_HISI) { + hvstate->asdr = env->spr[SPR_ASDR]; + } + + /* HEIR should be implemented for HV mode and saved here. */ + hvstate->srr0 = env->spr[SPR_SRR0]; + hvstate->srr1 = env->spr[SPR_SRR1]; + hvstate->sprg[0] = env->spr[SPR_SPRG0]; + hvstate->sprg[1] = env->spr[SPR_SPRG1]; + hvstate->sprg[2] = env->spr[SPR_SPRG2]; + hvstate->sprg[3] = env->spr[SPR_SPRG3]; + hvstate->pidr = env->spr[SPR_BOOKS_PID]; + hvstate->ppr = env->spr[SPR_PPR]; + + /* Is it okay to specify write length larger than actual data written? */ + address_space_unmap(CPU(cpu)->as, hvstate, len, len, true); + + len = sizeof(*regs); + regs = address_space_map(CPU(cpu)->as, regs_ptr, &len, true, + MEMTXATTRS_UNSPECIFIED); + if (!regs || len != sizeof(*regs)) { + address_space_unmap(CPU(cpu)->as, regs, len, 0, true); + r3_return = H_P2; + goto out_restore_l1; + } + + len = sizeof(env->gpr); + assert(len == sizeof(regs->gpr)); + memcpy(regs->gpr, env->gpr, len); + + regs->link = env->lr; + regs->ctr = env->ctr; + regs->xer = cpu_read_xer(env); + + cr = 0; + for (i = 0; i < 8; i++) { + cr |= (env->crf[i] & 15) << (4 * (7 - i)); + } + regs->ccr = cr; + + if (excp == POWERPC_EXCP_MCHECK || + excp == POWERPC_EXCP_RESET || + excp == POWERPC_EXCP_SYSCALL) { + regs->nip = env->spr[SPR_SRR0]; + regs->msr = env->spr[SPR_SRR1] & env->msr_mask; + } else { + regs->nip = env->spr[SPR_HSRR0]; + regs->msr = env->spr[SPR_HSRR1] & env->msr_mask; + } + + /* Is it okay to specify write length larger than actual data written? */ + address_space_unmap(CPU(cpu)->as, regs, len, len, true); + +out_restore_l1: + memcpy(env->gpr, spapr_cpu->nested_host_state->gpr, sizeof(env->gpr)); + env->lr = spapr_cpu->nested_host_state->lr; + env->ctr = spapr_cpu->nested_host_state->ctr; + memcpy(env->crf, spapr_cpu->nested_host_state->crf, sizeof(env->crf)); + env->cfar = spapr_cpu->nested_host_state->cfar; + env->xer = spapr_cpu->nested_host_state->xer; + env->so = spapr_cpu->nested_host_state->so; + env->ov = spapr_cpu->nested_host_state->ov; + env->ov32 = spapr_cpu->nested_host_state->ov32; + env->ca32 = spapr_cpu->nested_host_state->ca32; + env->msr = spapr_cpu->nested_host_state->msr; + env->nip = spapr_cpu->nested_host_state->nip; + + assert(env->spr[SPR_LPIDR] != 0); + env->spr[SPR_LPCR] = spapr_cpu->nested_host_state->spr[SPR_LPCR]; + env->spr[SPR_LPIDR] = spapr_cpu->nested_host_state->spr[SPR_LPIDR]; + env->spr[SPR_PCR] = spapr_cpu->nested_host_state->spr[SPR_PCR]; + env->spr[SPR_DPDES] = 0; + env->spr[SPR_HFSCR] = spapr_cpu->nested_host_state->spr[SPR_HFSCR]; + env->spr[SPR_SRR0] = spapr_cpu->nested_host_state->spr[SPR_SRR0]; + env->spr[SPR_SRR1] = spapr_cpu->nested_host_state->spr[SPR_SRR1]; + env->spr[SPR_SPRG0] = spapr_cpu->nested_host_state->spr[SPR_SPRG0]; + env->spr[SPR_SPRG1] = spapr_cpu->nested_host_state->spr[SPR_SPRG1]; + env->spr[SPR_SPRG2] = spapr_cpu->nested_host_state->spr[SPR_SPRG2]; + env->spr[SPR_SPRG3] = spapr_cpu->nested_host_state->spr[SPR_SPRG3]; + env->spr[SPR_BOOKS_PID] = spapr_cpu->nested_host_state->spr[SPR_BOOKS_PID]; + env->spr[SPR_PPR] = spapr_cpu->nested_host_state->spr[SPR_PPR]; + + /* + * Return the interrupt vector address from H_ENTER_NESTED to the L1 + * (or error code). + */ + env->gpr[3] = r3_return; + + env->tb_env->tb_offset -= spapr_cpu->nested_tb_offset; + spapr_cpu->in_nested = false; + + hreg_compute_hflags(env); + tlb_flush(cs); + env->reserve_addr = -1; /* Reset the reservation */ + + g_free(spapr_cpu->nested_host_state); + spapr_cpu->nested_host_state = NULL; +} + static void hypercall_register_types(void) { hypercall_register_softmmu(); @@ -1552,6 +1880,11 @@ static void hypercall_register_types(void) spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support); spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt); + + spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); + spapr_register_hypercall(KVMPPC_H_ENTER_NESTED, h_enter_nested); + spapr_register_hypercall(KVMPPC_H_TLB_INVALIDATE, h_tlb_invalidate); + spapr_register_hypercall(KVMPPC_H_COPY_TOFROM_GUEST, h_copy_tofrom_guest); } type_init(hypercall_register_types) diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index db01071858..81e5a1aea3 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -685,7 +685,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data) spapr_register_hypercall(H_STUFF_TCE, h_stuff_tce); } -static TypeInfo spapr_tce_table_info = { +static const TypeInfo spapr_tce_table_info = { .name = TYPE_SPAPR_TCE_TABLE, .parent = TYPE_DEVICE, .instance_size = sizeof(SpaprTceTable), diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 91de1052f2..c4c97da5de 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "qapi/error.h" #include "hw/ppc/spapr_drc.h" #include "hw/ppc/spapr_nvdimm.h" @@ -30,6 +31,10 @@ #include "hw/ppc/fdt.h" #include "qemu/range.h" #include "hw/ppc/spapr_numa.h" +#include "block/thread-pool.h" +#include "migration/vmstate.h" +#include "qemu/pmem.h" +#include "hw/qdev-properties.h" /* DIMM health bitmap bitmap indicators. Taken from kernel's papr_scm.c */ /* SCM device is unable to persist memory contents */ @@ -47,11 +52,25 @@ /* Have an explicit check for alignment */ QEMU_BUILD_BUG_ON(SPAPR_MINIMUM_SCM_BLOCK_SIZE % SPAPR_MEMORY_BLOCK_SIZE); +#define TYPE_SPAPR_NVDIMM "spapr-nvdimm" +OBJECT_DECLARE_TYPE(SpaprNVDIMMDevice, SPAPRNVDIMMClass, SPAPR_NVDIMM) + +struct SPAPRNVDIMMClass { + /* private */ + NVDIMMClass parent_class; + + /* public */ + void (*realize)(NVDIMMDevice *dimm, Error **errp); + void (*unrealize)(NVDIMMDevice *dimm, Error **errp); +}; + bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, uint64_t size, Error **errp) { const MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); const MachineState *ms = MACHINE(hotplug_dev); + PCDIMMDevice *dimm = PC_DIMM(nvdimm); + MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem); g_autofree char *uuidstr = NULL; QemuUUID uuid; int ret; @@ -89,6 +108,14 @@ bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, return false; } + if (object_dynamic_cast(OBJECT(nvdimm), TYPE_SPAPR_NVDIMM) && + (memory_region_get_fd(mr) < 0)) { + error_setg(errp, "spapr-nvdimm device requires the " + "memdev %s to be of memory-backend-file type", + object_get_canonical_path_component(OBJECT(dimm->hostmem))); + return false; + } + return true; } @@ -160,6 +187,20 @@ static int spapr_dt_nvdimm(SpaprMachineState *spapr, void *fdt, "operating-system"))); _FDT(fdt_setprop(fdt, child_offset, "ibm,cache-flush-required", NULL, 0)); + if (object_dynamic_cast(OBJECT(nvdimm), TYPE_SPAPR_NVDIMM)) { + bool is_pmem = false, pmem_override = false; + PCDIMMDevice *dimm = PC_DIMM(nvdimm); + HostMemoryBackend *hostmem = dimm->hostmem; + + is_pmem = object_property_get_bool(OBJECT(hostmem), "pmem", NULL); + pmem_override = object_property_get_bool(OBJECT(nvdimm), + "pmem-override", NULL); + if (!is_pmem || pmem_override) { + _FDT(fdt_setprop(fdt, child_offset, "ibm,hcall-flush-required", + NULL, 0)); + } + } + return child_offset; } @@ -375,6 +416,293 @@ static target_ulong h_scm_bind_mem(PowerPCCPU *cpu, SpaprMachineState *spapr, return H_SUCCESS; } +typedef struct SpaprNVDIMMDeviceFlushState { + uint64_t continue_token; + int64_t hcall_ret; + uint32_t drcidx; + + QLIST_ENTRY(SpaprNVDIMMDeviceFlushState) node; +} SpaprNVDIMMDeviceFlushState; + +typedef struct SpaprNVDIMMDevice SpaprNVDIMMDevice; +struct SpaprNVDIMMDevice { + /* private */ + NVDIMMDevice parent_obj; + + bool hcall_flush_required; + uint64_t nvdimm_flush_token; + QLIST_HEAD(, SpaprNVDIMMDeviceFlushState) pending_nvdimm_flush_states; + QLIST_HEAD(, SpaprNVDIMMDeviceFlushState) completed_nvdimm_flush_states; + + /* public */ + + /* + * The 'on' value for this property forced the qemu to enable the hcall + * flush for the nvdimm device even if the backend is a pmem + */ + bool pmem_override; +}; + +static int flush_worker_cb(void *opaque) +{ + SpaprNVDIMMDeviceFlushState *state = opaque; + SpaprDrc *drc = spapr_drc_by_index(state->drcidx); + PCDIMMDevice *dimm = PC_DIMM(drc->dev); + HostMemoryBackend *backend = MEMORY_BACKEND(dimm->hostmem); + int backend_fd = memory_region_get_fd(&backend->mr); + + if (object_property_get_bool(OBJECT(backend), "pmem", NULL)) { + MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem); + void *ptr = memory_region_get_ram_ptr(mr); + size_t size = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP, + NULL); + + /* flush pmem backend */ + pmem_persist(ptr, size); + } else { + /* flush raw backing image */ + if (qemu_fdatasync(backend_fd) < 0) { + error_report("papr_scm: Could not sync nvdimm to backend file: %s", + strerror(errno)); + return H_HARDWARE; + } + } + + return H_SUCCESS; +} + +static void spapr_nvdimm_flush_completion_cb(void *opaque, int hcall_ret) +{ + SpaprNVDIMMDeviceFlushState *state = opaque; + SpaprDrc *drc = spapr_drc_by_index(state->drcidx); + SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(drc->dev); + + state->hcall_ret = hcall_ret; + QLIST_REMOVE(state, node); + QLIST_INSERT_HEAD(&s_nvdimm->completed_nvdimm_flush_states, state, node); +} + +static int spapr_nvdimm_flush_post_load(void *opaque, int version_id) +{ + SpaprNVDIMMDevice *s_nvdimm = (SpaprNVDIMMDevice *)opaque; + SpaprNVDIMMDeviceFlushState *state; + ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); + HostMemoryBackend *backend = MEMORY_BACKEND(PC_DIMM(s_nvdimm)->hostmem); + bool is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL); + bool pmem_override = object_property_get_bool(OBJECT(s_nvdimm), + "pmem-override", NULL); + bool dest_hcall_flush_required = pmem_override || !is_pmem; + + if (!s_nvdimm->hcall_flush_required && dest_hcall_flush_required) { + error_report("The file backend for the spapr-nvdimm device %s at " + "source is a pmem, use pmem=on and pmem-override=off to " + "continue.", DEVICE(s_nvdimm)->id); + return -EINVAL; + } + if (s_nvdimm->hcall_flush_required && !dest_hcall_flush_required) { + error_report("The guest expects hcall-flush support for the " + "spapr-nvdimm device %s, use pmem_override=on to " + "continue.", DEVICE(s_nvdimm)->id); + return -EINVAL; + } + + QLIST_FOREACH(state, &s_nvdimm->pending_nvdimm_flush_states, node) { + thread_pool_submit_aio(pool, flush_worker_cb, state, + spapr_nvdimm_flush_completion_cb, state); + } + + return 0; +} + +static const VMStateDescription vmstate_spapr_nvdimm_flush_state = { + .name = "spapr_nvdimm_flush_state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(continue_token, SpaprNVDIMMDeviceFlushState), + VMSTATE_INT64(hcall_ret, SpaprNVDIMMDeviceFlushState), + VMSTATE_UINT32(drcidx, SpaprNVDIMMDeviceFlushState), + VMSTATE_END_OF_LIST() + }, +}; + +const VMStateDescription vmstate_spapr_nvdimm_states = { + .name = "spapr_nvdimm_states", + .version_id = 1, + .minimum_version_id = 1, + .post_load = spapr_nvdimm_flush_post_load, + .fields = (VMStateField[]) { + VMSTATE_BOOL(hcall_flush_required, SpaprNVDIMMDevice), + VMSTATE_UINT64(nvdimm_flush_token, SpaprNVDIMMDevice), + VMSTATE_QLIST_V(completed_nvdimm_flush_states, SpaprNVDIMMDevice, 1, + vmstate_spapr_nvdimm_flush_state, + SpaprNVDIMMDeviceFlushState, node), + VMSTATE_QLIST_V(pending_nvdimm_flush_states, SpaprNVDIMMDevice, 1, + vmstate_spapr_nvdimm_flush_state, + SpaprNVDIMMDeviceFlushState, node), + VMSTATE_END_OF_LIST() + }, +}; + +/* + * Assign a token and reserve it for the new flush state. + */ +static SpaprNVDIMMDeviceFlushState *spapr_nvdimm_init_new_flush_state( + SpaprNVDIMMDevice *spapr_nvdimm) +{ + SpaprNVDIMMDeviceFlushState *state; + + state = g_malloc0(sizeof(*state)); + + spapr_nvdimm->nvdimm_flush_token++; + /* Token zero is presumed as no job pending. Assert on overflow to zero */ + g_assert(spapr_nvdimm->nvdimm_flush_token != 0); + + state->continue_token = spapr_nvdimm->nvdimm_flush_token; + + QLIST_INSERT_HEAD(&spapr_nvdimm->pending_nvdimm_flush_states, state, node); + + return state; +} + +/* + * spapr_nvdimm_finish_flushes + * Waits for all pending flush requests to complete + * their execution and free the states + */ +void spapr_nvdimm_finish_flushes(void) +{ + SpaprNVDIMMDeviceFlushState *state, *next; + GSList *list, *nvdimms; + + /* + * Called on reset path, the main loop thread which calls + * the pending BHs has gotten out running in the reset path, + * finally reaching here. Other code path being guest + * h_client_architecture_support, thats early boot up. + */ + nvdimms = nvdimm_get_device_list(); + for (list = nvdimms; list; list = list->next) { + NVDIMMDevice *nvdimm = list->data; + if (object_dynamic_cast(OBJECT(nvdimm), TYPE_SPAPR_NVDIMM)) { + SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(nvdimm); + while (!QLIST_EMPTY(&s_nvdimm->pending_nvdimm_flush_states)) { + aio_poll(qemu_get_aio_context(), true); + } + + QLIST_FOREACH_SAFE(state, &s_nvdimm->completed_nvdimm_flush_states, + node, next) { + QLIST_REMOVE(state, node); + g_free(state); + } + } + } + g_slist_free(nvdimms); +} + +/* + * spapr_nvdimm_get_flush_status + * Fetches the status of the hcall worker and returns + * H_LONG_BUSY_ORDER_10_MSEC if the worker is still running. + */ +static int spapr_nvdimm_get_flush_status(SpaprNVDIMMDevice *s_nvdimm, + uint64_t token) +{ + SpaprNVDIMMDeviceFlushState *state, *node; + + QLIST_FOREACH(state, &s_nvdimm->pending_nvdimm_flush_states, node) { + if (state->continue_token == token) { + return H_LONG_BUSY_ORDER_10_MSEC; + } + } + + QLIST_FOREACH_SAFE(state, &s_nvdimm->completed_nvdimm_flush_states, + node, node) { + if (state->continue_token == token) { + int ret = state->hcall_ret; + QLIST_REMOVE(state, node); + g_free(state); + return ret; + } + } + + /* If not found in complete list too, invalid token */ + return H_P2; +} + +/* + * H_SCM_FLUSH + * Input: drc_index, continue-token + * Out: continue-token + * Return Value: H_SUCCESS, H_Parameter, H_P2, H_LONG_BUSY_ORDER_10_MSEC, + * H_UNSUPPORTED + * + * Given a DRC Index Flush the data to backend NVDIMM device. The hcall returns + * H_LONG_BUSY_ORDER_10_MSEC when the flush takes longer time and the hcall + * needs to be issued multiple times in order to be completely serviced. The + * continue-token from the output to be passed in the argument list of + * subsequent hcalls until the hcall is completely serviced at which point + * H_SUCCESS or other error is returned. + */ +static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + int ret; + uint32_t drc_index = args[0]; + uint64_t continue_token = args[1]; + SpaprDrc *drc = spapr_drc_by_index(drc_index); + PCDIMMDevice *dimm; + HostMemoryBackend *backend = NULL; + SpaprNVDIMMDeviceFlushState *state; + ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); + int fd; + + if (!drc || !drc->dev || + spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) { + return H_PARAMETER; + } + + dimm = PC_DIMM(drc->dev); + if (!object_dynamic_cast(OBJECT(dimm), TYPE_SPAPR_NVDIMM)) { + return H_PARAMETER; + } + if (continue_token == 0) { + bool is_pmem = false, pmem_override = false; + backend = MEMORY_BACKEND(dimm->hostmem); + fd = memory_region_get_fd(&backend->mr); + + if (fd < 0) { + return H_UNSUPPORTED; + } + + is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL); + pmem_override = object_property_get_bool(OBJECT(dimm), + "pmem-override", NULL); + if (is_pmem && !pmem_override) { + return H_UNSUPPORTED; + } + + state = spapr_nvdimm_init_new_flush_state(SPAPR_NVDIMM(dimm)); + if (!state) { + return H_HARDWARE; + } + + state->drcidx = drc_index; + + thread_pool_submit_aio(pool, flush_worker_cb, state, + spapr_nvdimm_flush_completion_cb, state); + + continue_token = state->continue_token; + } + + ret = spapr_nvdimm_get_flush_status(SPAPR_NVDIMM(dimm), continue_token); + if (H_IS_LONG_BUSY(ret)) { + args[0] = continue_token; + } + + return ret; +} + static target_ulong h_scm_unbind_mem(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, target_ulong *args) { @@ -523,6 +851,70 @@ static void spapr_scm_register_types(void) spapr_register_hypercall(H_SCM_UNBIND_MEM, h_scm_unbind_mem); spapr_register_hypercall(H_SCM_UNBIND_ALL, h_scm_unbind_all); spapr_register_hypercall(H_SCM_HEALTH, h_scm_health); + spapr_register_hypercall(H_SCM_FLUSH, h_scm_flush); } type_init(spapr_scm_register_types) + +static void spapr_nvdimm_realize(NVDIMMDevice *dimm, Error **errp) +{ + SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(dimm); + HostMemoryBackend *backend = MEMORY_BACKEND(PC_DIMM(dimm)->hostmem); + bool is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL); + bool pmem_override = object_property_get_bool(OBJECT(dimm), "pmem-override", + NULL); + if (!is_pmem || pmem_override) { + s_nvdimm->hcall_flush_required = true; + } + + vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, + &vmstate_spapr_nvdimm_states, dimm); +} + +static void spapr_nvdimm_unrealize(NVDIMMDevice *dimm) +{ + vmstate_unregister(NULL, &vmstate_spapr_nvdimm_states, dimm); +} + +static Property spapr_nvdimm_properties[] = { +#ifdef CONFIG_LIBPMEM + DEFINE_PROP_BOOL("pmem-override", SpaprNVDIMMDevice, pmem_override, false), +#endif + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_nvdimm_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + NVDIMMClass *nvc = NVDIMM_CLASS(oc); + + nvc->realize = spapr_nvdimm_realize; + nvc->unrealize = spapr_nvdimm_unrealize; + + device_class_set_props(dc, spapr_nvdimm_properties); +} + +static void spapr_nvdimm_init(Object *obj) +{ + SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(obj); + + s_nvdimm->hcall_flush_required = false; + QLIST_INIT(&s_nvdimm->pending_nvdimm_flush_states); + QLIST_INIT(&s_nvdimm->completed_nvdimm_flush_states); +} + +static TypeInfo spapr_nvdimm_info = { + .name = TYPE_SPAPR_NVDIMM, + .parent = TYPE_NVDIMM, + .class_init = spapr_nvdimm_class_init, + .class_size = sizeof(SPAPRNVDIMMClass), + .instance_size = sizeof(SpaprNVDIMMDevice), + .instance_init = spapr_nvdimm_init, +}; + +static void spapr_nvdimm_register_types(void) +{ + type_register_static(&spapr_nvdimm_info); +} + +type_init(spapr_nvdimm_register_types) diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c index 882c9b4854..0e893f3189 100644 --- a/hw/remote/proxy-memory-listener.c +++ b/hw/remote/proxy-memory-listener.c @@ -16,6 +16,7 @@ #include "exec/cpu-common.h" #include "exec/ram_addr.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "hw/remote/mpqemu-link.h" #include "hw/remote/proxy-memory-listener.h" diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig index f06e133b8a..730c272bc5 100644 --- a/hw/rtc/Kconfig +++ b/hw/rtc/Kconfig @@ -1,10 +1,12 @@ config DS1338 bool depends on I2C + default y if I2C_DEVICES config M41T80 bool depends on I2C + default y if I2C_DEVICES config M48T59 bool diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 01b58ebc70..4b2bdd94b3 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -1392,7 +1392,7 @@ static const TypeInfo s390_pci_device_info = { .class_init = s390_pci_device_class_init, }; -static TypeInfo s390_pci_iommu_info = { +static const TypeInfo s390_pci_iommu_info = { .name = TYPE_S390_PCI_IOMMU, .parent = TYPE_OBJECT, .instance_size = sizeof(S390PCIIOMMU), diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 89c30a8a91..eff74479f4 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -460,7 +460,7 @@ static void sclp_class_init(ObjectClass *oc, void *data) sc->service_interrupt = service_interrupt; } -static TypeInfo sclp_info = { +static const TypeInfo sclp_info = { .name = TYPE_SCLP, .parent = TYPE_DEVICE, .instance_init = sclp_init, diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c index ec855811ae..9d0cbfbce2 100644 --- a/hw/s390x/tod-kvm.c +++ b/hw/s390x/tod-kvm.c @@ -147,7 +147,7 @@ static void kvm_s390_tod_init(Object *obj) td->stopped = false; } -static TypeInfo kvm_s390_tod_info = { +static const TypeInfo kvm_s390_tod_info = { .name = TYPE_KVM_S390_TOD, .parent = TYPE_S390_TOD, .instance_size = sizeof(S390TODState), diff --git a/hw/s390x/tod-tcg.c b/hw/s390x/tod-tcg.c index 7646b4aa38..2d540dba65 100644 --- a/hw/s390x/tod-tcg.c +++ b/hw/s390x/tod-tcg.c @@ -73,7 +73,7 @@ static void qemu_s390_tod_init(Object *obj) } } -static TypeInfo qemu_s390_tod_info = { +static const TypeInfo qemu_s390_tod_info = { .name = TYPE_QEMU_S390_TOD, .parent = TYPE_S390_TOD, .instance_size = sizeof(S390TODState), diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c index fd5a36bf24..c81b1c0338 100644 --- a/hw/s390x/tod.c +++ b/hw/s390x/tod.c @@ -123,7 +123,7 @@ static void s390_tod_class_init(ObjectClass *oc, void *data) dc->user_creatable = false; } -static TypeInfo s390_tod_info = { +static const TypeInfo s390_tod_info = { .name = TYPE_S390_TOD, .parent = TYPE_DEVICE, .instance_size = sizeof(S390TODState), diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 4c431adb77..c8773f73f7 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2352,7 +2352,7 @@ static void lsi53c810_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_LSI_53C810; } -static TypeInfo lsi53c810_info = { +static const TypeInfo lsi53c810_info = { .name = TYPE_LSI53C810, .parent = TYPE_LSI53C895A, .class_init = lsi53c810_class_init, diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index cd43945827..d5dfb412ba 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -28,6 +28,7 @@ #include "hw/pci/msix.h" #include "qemu/iov.h" #include "qemu/module.h" +#include "qemu/hw-version.h" #include "hw/scsi/scsi.h" #include "scsi/constants.h" #include "trace.h" diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 4057e04ce8..b2e2bc3c96 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -3,6 +3,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/option.h" +#include "qemu/hw-version.h" #include "hw/qdev-properties.h" #include "hw/scsi/scsi.h" #include "migration/qemu-file-types.h" diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 9c0dc7b946..3666b8d946 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -25,6 +25,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/module.h" +#include "qemu/hw-version.h" #include "hw/scsi/scsi.h" #include "migration/qemu-file-types.h" #include "migration/vmstate.h" diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c index de5bc49e68..041e45c680 100644 --- a/hw/sd/allwinner-sdhost.c +++ b/hw/sd/allwinner-sdhost.c @@ -835,7 +835,7 @@ static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data) sc->max_desc_size = 64 * KiB; } -static TypeInfo allwinner_sdhost_info = { +static const TypeInfo allwinner_sdhost_info = { .name = TYPE_AW_SDHOST, .parent = TYPE_SYS_BUS_DEVICE, .instance_init = allwinner_sdhost_init, diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index df1bdf1fa4..be8cafd65f 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -198,7 +198,7 @@ static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) device_class_set_props(dc, aspeed_sdhci_properties); } -static TypeInfo aspeed_sdhci_info = { +static const TypeInfo aspeed_sdhci_info = { .name = TYPE_ASPEED_SDHCI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(AspeedSDHCIState), diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c index 088a7ac6ed..9431c35914 100644 --- a/hw/sd/bcm2835_sdhost.c +++ b/hw/sd/bcm2835_sdhost.c @@ -436,7 +436,7 @@ static void bcm2835_sdhost_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bcm2835_sdhost; } -static TypeInfo bcm2835_sdhost_info = { +static const TypeInfo bcm2835_sdhost_info = { .name = TYPE_BCM2835_SDHOST, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BCM2835SDHostState), diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c index 56b8bae1c3..75db34befe 100644 --- a/hw/sd/cadence_sdhci.c +++ b/hw/sd/cadence_sdhci.c @@ -175,7 +175,7 @@ static void cadence_sdhci_class_init(ObjectClass *classp, void *data) dc->vmsd = &vmstate_cadence_sdhci; } -static TypeInfo cadence_sdhci_info = { +static const TypeInfo cadence_sdhci_info = { .name = TYPE_CADENCE_SDHCI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CadenceSDHCIState), diff --git a/hw/sd/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c index ef503365df..b2f5b4a542 100644 --- a/hw/sd/npcm7xx_sdhci.c +++ b/hw/sd/npcm7xx_sdhci.c @@ -166,7 +166,7 @@ static void npcm7xx_sdhci_instance_init(Object *obj) TYPE_SYSBUS_SDHCI); } -static TypeInfo npcm7xx_sdhci_info = { +static const TypeInfo npcm7xx_sdhci_info = { .name = TYPE_NPCM7XX_SDHCI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(NPCM7xxSDHCIState), diff --git a/hw/sensor/Kconfig b/hw/sensor/Kconfig index b317f91b7b..215944decc 100644 --- a/hw/sensor/Kconfig +++ b/hw/sensor/Kconfig @@ -1,18 +1,22 @@ config TMP105 bool depends on I2C + default y if I2C_DEVICES config TMP421 bool depends on I2C + default y if I2C_DEVICES config DPS310 bool depends on I2C + default y if I2C_DEVICES config EMC141X bool depends on I2C + default y if I2C_DEVICES config ADM1272 bool @@ -25,3 +29,4 @@ config MAX34451 config LSM303DLHC_MAG bool depends on I2C + default y if I2C_DEVICES diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c index 7233068a37..5e959b6d09 100644 --- a/hw/timer/a9gtimer.c +++ b/hw/timer/a9gtimer.c @@ -318,6 +318,12 @@ static void a9_gtimer_realize(DeviceState *dev, Error **errp) } } +static bool vmstate_a9_gtimer_control_needed(void *opaque) +{ + A9GTimerState *s = opaque; + return s->control != 0; +} + static const VMStateDescription vmstate_a9_gtimer_per_cpu = { .name = "arm.cortex-a9-global-timer.percpu", .version_id = 1, @@ -331,6 +337,17 @@ static const VMStateDescription vmstate_a9_gtimer_per_cpu = { } }; +static const VMStateDescription vmstate_a9_gtimer_control = { + .name = "arm.cortex-a9-global-timer.control", + .version_id = 1, + .minimum_version_id = 1, + .needed = vmstate_a9_gtimer_control_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(control, A9GTimerState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_a9_gtimer = { .name = "arm.cortex-a9-global-timer", .version_id = 1, @@ -344,6 +361,10 @@ static const VMStateDescription vmstate_a9_gtimer = { 1, vmstate_a9_gtimer_per_cpu, A9GTimerPerCPU), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_a9_gtimer_control, + NULL } }; diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 58ebd1469c..aa9c00aad3 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -18,6 +18,7 @@ #include "qemu/module.h" #include "qapi/error.h" +#include "exec/address-spaces.h" #include "hw/qdev-properties.h" #include "hw/pci/pci_ids.h" #include "hw/acpi/tpm.h" diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c index 274e9aa4b0..6dbb9f41e4 100644 --- a/hw/tpm/tpm_ppi.c +++ b/hw/tpm/tpm_ppi.c @@ -14,9 +14,9 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "sysemu/memory_mapping.h" #include "migration/vmstate.h" +#include "hw/qdev-core.h" #include "hw/acpi/tpm.h" #include "tpm_ppi.h" #include "trace.h" @@ -44,7 +44,7 @@ void tpm_ppi_reset(TPMPPI *tpmppi) } } -void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, +void tpm_ppi_init(TPMPPI *tpmppi, MemoryRegion *m, hwaddr addr, Object *obj) { tpmppi->buf = qemu_memalign(qemu_real_host_page_size, diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h index 6f773c25a0..bf5d4a300f 100644 --- a/hw/tpm/tpm_ppi.h +++ b/hw/tpm/tpm_ppi.h @@ -12,7 +12,7 @@ #ifndef TPM_TPM_PPI_H #define TPM_TPM_PPI_H -#include "exec/address-spaces.h" +#include "exec/memory.h" typedef struct TPMPPI { MemoryRegion ram; @@ -29,7 +29,7 @@ typedef struct TPMPPI { * Register the TPM PPI memory region at @addr on the given address * space for the object @obj. **/ -void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, +void tpm_ppi_init(TPMPPI *tpmppi, MemoryRegion *m, hwaddr addr, Object *obj); /** diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 1c7ae97c30..bdd6d1ffaf 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -461,14 +461,14 @@ static const uint8_t qemu_mouse_hid_report_descriptor[] = { 0xa1, 0x00, /* Collection (Physical) */ 0x05, 0x09, /* Usage Page (Button) */ 0x19, 0x01, /* Usage Minimum (1) */ - 0x29, 0x03, /* Usage Maximum (3) */ + 0x29, 0x05, /* Usage Maximum (5) */ 0x15, 0x00, /* Logical Minimum (0) */ 0x25, 0x01, /* Logical Maximum (1) */ - 0x95, 0x03, /* Report Count (3) */ + 0x95, 0x05, /* Report Count (5) */ 0x75, 0x01, /* Report Size (1) */ 0x81, 0x02, /* Input (Data, Variable, Absolute) */ 0x95, 0x01, /* Report Count (1) */ - 0x75, 0x05, /* Report Size (5) */ + 0x75, 0x03, /* Report Size (3) */ 0x81, 0x01, /* Input (Constant) */ 0x05, 0x01, /* Usage Page (Generic Desktop) */ 0x09, 0x30, /* Usage (X) */ diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index c1d1694fd0..1e6ac76bef 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -2106,7 +2106,7 @@ static void usb_mtp_class_initfn(ObjectClass *klass, void *data) device_class_set_props(dc, mtp_properties); } -static TypeInfo mtp_info = { +static const TypeInfo mtp_info = { .name = TYPE_USB_MTP, .parent = TYPE_USB_DEVICE, .instance_size = sizeof(MTPState), diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index d0d46dd0a4..2b35cb6cdd 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1801,7 +1801,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } -static TypeInfo usb_host_dev_info = { +static const TypeInfo usb_host_dev_info = { .name = TYPE_USB_HOST_DEVICE, .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHostDevice), diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c index d4685709a3..afe3fe7efc 100644 --- a/hw/vfio/igd.c +++ b/hw/vfio/igd.c @@ -199,7 +199,7 @@ static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_ISA; } -static TypeInfo vfio_pci_igd_lpc_bridge_info = { +static const TypeInfo vfio_pci_igd_lpc_bridge_info = { .name = "vfio-pci-igd-lpc-bridge", .parent = TYPE_PCI_DEVICE, .class_init = vfio_pci_igd_lpc_bridge_class_init, diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 9a4f491b54..e6c1b0aa46 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -17,6 +17,7 @@ #include "qemu/iov.h" #include "qemu/module.h" #include "qemu/timer.h" +#include "qemu/madvise.h" #include "hw/virtio/virtio.h" #include "hw/mem/pc-dimm.h" #include "hw/qdev-properties.h" diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index d1aeb90a31..5419dca75e 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -182,7 +182,7 @@ static void virtio_pmem_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } -static TypeInfo virtio_pmem_info = { +static const TypeInfo virtio_pmem_info = { .name = TYPE_VIRTIO_PMEM, .parent = TYPE_VIRTIO_DEVICE, .class_size = sizeof(VirtIOPMEMClass), diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 35d8e93976..227e10ba56 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -40,8 +40,6 @@ typedef ram_addr_t tb_page_addr_t; #define TB_PAGE_ADDR_FMT RAM_ADDR_FMT #endif -#include "qemu/log.h" - void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns); void restore_state_to_opc(CPUArchState *env, TranslationBlock *tb, target_ulong *data); diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h index 664701b759..6cbedf9e0c 100644 --- a/include/exec/ramblock.h +++ b/include/exec/ramblock.h @@ -21,6 +21,8 @@ #ifndef CONFIG_USER_ONLY #include "cpu-common.h" +#include "qemu/rcu.h" +#include "exec/ramlist.h" struct RAMBlock { struct rcu_head rcu; diff --git a/include/hw/m68k/mcf.h b/include/hw/m68k/mcf.h index decf17ce42..8cbd587bbf 100644 --- a/include/hw/m68k/mcf.h +++ b/include/hw/m68k/mcf.h @@ -2,6 +2,7 @@ #define HW_MCF_H /* Motorola ColdFire device prototypes. */ +#include "exec/hwaddr.h" #include "target/m68k/cpu-qom.h" /* mcf_uart.c */ diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h index bcf62f825c..cf8f59be44 100644 --- a/include/hw/mem/nvdimm.h +++ b/include/hw/mem/nvdimm.h @@ -103,6 +103,8 @@ struct NVDIMMClass { /* write @size bytes from @buf to NVDIMM label data at @offset. */ void (*write_label_data)(NVDIMMDevice *nvdimm, const void *buf, uint64_t size, uint64_t offset); + void (*realize)(NVDIMMDevice *nvdimm, Error **errp); + void (*unrealize)(NVDIMMDevice *nvdimm); }; #define NVDIMM_DSM_MEM_FILE "etc/acpi/nvdimm-mem" diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h index 1473e6db62..322bebe555 100644 --- a/include/hw/mem/pc-dimm.h +++ b/include/hw/mem/pc-dimm.h @@ -63,6 +63,7 @@ struct PCDIMMDeviceClass { /* public */ void (*realize)(PCDIMMDevice *dimm, Error **errp); + void (*unrealize)(PCDIMMDevice *dimm); }; void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index 93e614cffd..b0ba4bd6b9 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -54,6 +54,9 @@ struct ppc_tb_t { uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset); clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); +void cpu_ppc_hdecr_init(CPUPPCState *env); +void cpu_ppc_hdecr_exit(CPUPPCState *env); + /* Embedded PowerPC DCR management */ typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn); typedef void (*dcr_write_cb)(void *opaque, int dcrn, uint32_t val); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index ee7504b976..f5c33dcc86 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -197,6 +197,9 @@ struct SpaprMachineState { bool has_graphics; uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */ + /* Nested HV support (TCG only) */ + uint64_t nested_ptcr; + Notifier epow_notifier; QTAILQ_HEAD(, SpaprEventLogEntry) pending_events; bool use_hotplug_event_source; @@ -341,6 +344,7 @@ struct SpaprMachineState { #define H_P7 -60 #define H_P8 -61 #define H_P9 -62 +#define H_UNSUPPORTED -67 #define H_OVERLAP -68 #define H_UNSUPPORTED_FLAG -256 #define H_MULTI_THREADS_ACTIVE -9005 @@ -559,8 +563,9 @@ struct SpaprMachineState { #define H_SCM_UNBIND_ALL 0x3FC #define H_SCM_HEALTH 0x400 #define H_RPT_INVALIDATE 0x448 +#define H_SCM_FLUSH 0x44C -#define MAX_HCALL_OPCODE H_RPT_INVALIDATE +#define MAX_HCALL_OPCODE H_SCM_FLUSH /* The hcalls above are standardized in PAPR and implemented by pHyp * as well. @@ -577,7 +582,14 @@ struct SpaprMachineState { #define KVMPPC_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3) /* 0x4 was used for KVMPPC_H_UPDATE_PHANDLE in SLOF */ #define KVMPPC_H_VOF_CLIENT (KVMPPC_HCALL_BASE + 0x5) -#define KVMPPC_HCALL_MAX KVMPPC_H_VOF_CLIENT + +/* Platform-specific hcalls used for nested HV KVM */ +#define KVMPPC_H_SET_PARTITION_TABLE (KVMPPC_HCALL_BASE + 0x800) +#define KVMPPC_H_ENTER_NESTED (KVMPPC_HCALL_BASE + 0x804) +#define KVMPPC_H_TLB_INVALIDATE (KVMPPC_HCALL_BASE + 0x808) +#define KVMPPC_H_COPY_TOFROM_GUEST (KVMPPC_HCALL_BASE + 0x80C) + +#define KVMPPC_HCALL_MAX KVMPPC_H_COPY_TOFROM_GUEST /* * The hcall range 0xEF00 to 0xEF80 is reserved for use in facilitating @@ -587,6 +599,65 @@ struct SpaprMachineState { #define SVM_H_TPM_COMM 0xEF10 #define SVM_HCALL_MAX SVM_H_TPM_COMM +/* + * Register state for entering a nested guest with H_ENTER_NESTED. + * New member must be added at the end. + */ +struct kvmppc_hv_guest_state { + uint64_t version; /* version of this structure layout, must be first */ + uint32_t lpid; + uint32_t vcpu_token; + /* These registers are hypervisor privileged (at least for writing) */ + uint64_t lpcr; + uint64_t pcr; + uint64_t amor; + uint64_t dpdes; + uint64_t hfscr; + int64_t tb_offset; + uint64_t dawr0; + uint64_t dawrx0; + uint64_t ciabr; + uint64_t hdec_expiry; + uint64_t purr; + uint64_t spurr; + uint64_t ic; + uint64_t vtb; + uint64_t hdar; + uint64_t hdsisr; + uint64_t heir; + uint64_t asdr; + /* These are OS privileged but need to be set late in guest entry */ + uint64_t srr0; + uint64_t srr1; + uint64_t sprg[4]; + uint64_t pidr; + uint64_t cfar; + uint64_t ppr; + /* Version 1 ends here */ + uint64_t dawr1; + uint64_t dawrx1; + /* Version 2 ends here */ +}; + +/* Latest version of hv_guest_state structure */ +#define HV_GUEST_STATE_VERSION 2 + +/* Linux 64-bit powerpc pt_regs struct, used by nested HV */ +struct kvmppc_pt_regs { + uint64_t gpr[32]; + uint64_t nip; + uint64_t msr; + uint64_t orig_gpr3; /* Used for restarting system calls */ + uint64_t ctr; + uint64_t link; + uint64_t xer; + uint64_t ccr; + uint64_t softe; /* Soft enabled/disabled */ + uint64_t trap; /* Reason for being here */ + uint64_t dar; /* Fault registers */ + uint64_t dsisr; /* on 4xx/Book-E used for ESR */ + uint64_t result; /* Result of a system call */ +}; typedef struct SpaprDeviceTreeUpdateHeader { uint32_t version_id; @@ -604,6 +675,9 @@ typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, SpaprMachineState *sm, void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); + +void spapr_exit_nested(PowerPCCPU *cpu, int excp); + target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong shift); target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, SpaprMachineState *spapr, diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index dab3dfc76c..b560514560 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -48,6 +48,11 @@ typedef struct SpaprCpuState { bool prod; /* not migrated, only used to improve dispatch latencies */ struct ICPState *icp; struct XiveTCTX *tctx; + + /* Fields for nested-HV support */ + bool in_nested; /* true while the L2 is executing */ + CPUPPCState *nested_host_state; /* holds the L1 state while L2 executes */ + int64_t nested_tb_offset; /* L1->L2 TB offset */ } SpaprCpuState; static inline SpaprCpuState *spapr_cpu_state(PowerPCCPU *cpu) diff --git a/include/hw/ppc/spapr_nvdimm.h b/include/hw/ppc/spapr_nvdimm.h index 764f999f54..e9436cb6ef 100644 --- a/include/hw/ppc/spapr_nvdimm.h +++ b/include/hw/ppc/spapr_nvdimm.h @@ -21,5 +21,6 @@ void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt); bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, uint64_t size, Error **errp); void spapr_add_nvdimm(DeviceState *dev, uint64_t slot); +void spapr_nvdimm_finish_flushes(void); #endif diff --git a/include/hw/tricore/triboard.h b/include/hw/tricore/triboard.h index f3844be447..094c8bd563 100644 --- a/include/hw/tricore/triboard.h +++ b/include/hw/tricore/triboard.h @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/boards.h" -#include "hw/arm/boot.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" #include "qom/object.h" diff --git a/include/qemu/cacheinfo.h b/include/qemu/cacheinfo.h new file mode 100644 index 0000000000..019a157ea0 --- /dev/null +++ b/include/qemu/cacheinfo.h @@ -0,0 +1,21 @@ +/* + * QEMU host cacheinfo information + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_CACHEINFO_H +#define QEMU_CACHEINFO_H + +/* + * These variables represent our best guess at the host icache and + * dcache sizes, expressed both as the size in bytes and as the + * base-2 log of the size in bytes. They are initialized at startup + * (via an attribute 'constructor' function). + */ +extern int qemu_icache_linesize; +extern int qemu_icache_linesize_log; +extern int qemu_dcache_linesize; +extern int qemu_dcache_linesize_log; + +#endif diff --git a/include/qemu/hw-version.h b/include/qemu/hw-version.h new file mode 100644 index 0000000000..730a8c904d --- /dev/null +++ b/include/qemu/hw-version.h @@ -0,0 +1,27 @@ +/* + * QEMU "hardware version" machinery + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_HW_VERSION_H +#define QEMU_HW_VERSION_H + +/* + * Starting on QEMU 2.5, qemu_hw_version() returns "2.5+" by default + * instead of QEMU_VERSION, so setting hw_version on MachineClass + * is no longer mandatory. + * + * Do NOT change this string, or it will break compatibility on all + * machine classes that don't set hw_version. + */ +#define QEMU_HW_VERSION "2.5+" + +/* QEMU "hardware version" setting. Used to replace code that exposed + * QEMU_VERSION to guests in the past and need to keep compatibility. + * Do not use qemu_hw_version() in new code. + */ +void qemu_set_hw_version(const char *); +const char *qemu_hw_version(void); + +#endif diff --git a/include/qemu/madvise.h b/include/qemu/madvise.h new file mode 100644 index 0000000000..e155f59a0d --- /dev/null +++ b/include/qemu/madvise.h @@ -0,0 +1,95 @@ +/* + * QEMU madvise wrapper functions + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_MADVISE_H +#define QEMU_MADVISE_H + +#define QEMU_MADV_INVALID -1 + +#if defined(CONFIG_MADVISE) + +#define QEMU_MADV_WILLNEED MADV_WILLNEED +#define QEMU_MADV_DONTNEED MADV_DONTNEED +#ifdef MADV_DONTFORK +#define QEMU_MADV_DONTFORK MADV_DONTFORK +#else +#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID +#endif +#ifdef MADV_MERGEABLE +#define QEMU_MADV_MERGEABLE MADV_MERGEABLE +#else +#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID +#endif +#ifdef MADV_UNMERGEABLE +#define QEMU_MADV_UNMERGEABLE MADV_UNMERGEABLE +#else +#define QEMU_MADV_UNMERGEABLE QEMU_MADV_INVALID +#endif +#ifdef MADV_DODUMP +#define QEMU_MADV_DODUMP MADV_DODUMP +#else +#define QEMU_MADV_DODUMP QEMU_MADV_INVALID +#endif +#ifdef MADV_DONTDUMP +#define QEMU_MADV_DONTDUMP MADV_DONTDUMP +#else +#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID +#endif +#ifdef MADV_HUGEPAGE +#define QEMU_MADV_HUGEPAGE MADV_HUGEPAGE +#else +#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID +#endif +#ifdef MADV_NOHUGEPAGE +#define QEMU_MADV_NOHUGEPAGE MADV_NOHUGEPAGE +#else +#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID +#endif +#ifdef MADV_REMOVE +#define QEMU_MADV_REMOVE MADV_REMOVE +#else +#define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED +#endif +#ifdef MADV_POPULATE_WRITE +#define QEMU_MADV_POPULATE_WRITE MADV_POPULATE_WRITE +#else +#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID +#endif + +#elif defined(CONFIG_POSIX_MADVISE) + +#define QEMU_MADV_WILLNEED POSIX_MADV_WILLNEED +#define QEMU_MADV_DONTNEED POSIX_MADV_DONTNEED +#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID +#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID +#define QEMU_MADV_UNMERGEABLE QEMU_MADV_INVALID +#define QEMU_MADV_DODUMP QEMU_MADV_INVALID +#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID +#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID +#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID +#define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED +#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID + +#else /* no-op */ + +#define QEMU_MADV_WILLNEED QEMU_MADV_INVALID +#define QEMU_MADV_DONTNEED QEMU_MADV_INVALID +#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID +#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID +#define QEMU_MADV_UNMERGEABLE QEMU_MADV_INVALID +#define QEMU_MADV_DODUMP QEMU_MADV_INVALID +#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID +#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID +#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID +#define QEMU_MADV_REMOVE QEMU_MADV_INVALID +#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID + +#endif + +int qemu_madvise(void *addr, size_t len, int advice); + +#endif diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h index 90d0eee705..5076695cc8 100644 --- a/include/qemu/mmap-alloc.h +++ b/include/qemu/mmap-alloc.h @@ -35,4 +35,27 @@ void *qemu_ram_mmap(int fd, void qemu_ram_munmap(int fd, void *ptr, size_t size); +/* + * Abstraction of PROT_ and MAP_ flags as passed to mmap(), for example, + * consumed by qemu_ram_mmap(). + */ + +/* Map PROT_READ instead of PROT_READ | PROT_WRITE. */ +#define QEMU_MAP_READONLY (1 << 0) + +/* Use MAP_SHARED instead of MAP_PRIVATE. */ +#define QEMU_MAP_SHARED (1 << 1) + +/* + * Use MAP_SYNC | MAP_SHARED_VALIDATE if supported. Ignored without + * QEMU_MAP_SHARED. If mapping fails, warn and fallback to !QEMU_MAP_SYNC. + */ +#define QEMU_MAP_SYNC (1 << 2) + +/* + * Use MAP_NORESERVE to skip reservation of swap space (or huge pages if + * applicable). Bail out if not supported/effective. + */ +#define QEMU_MAP_NORESERVE (1 << 3) + #endif diff --git a/include/qemu/mprotect.h b/include/qemu/mprotect.h new file mode 100644 index 0000000000..1e83d1433e --- /dev/null +++ b/include/qemu/mprotect.h @@ -0,0 +1,14 @@ +/* + * QEMU mprotect functions + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_MPROTECT_H +#define QEMU_MPROTECT_H + +int qemu_mprotect_rw(void *addr, size_t size); +int qemu_mprotect_rwx(void *addr, size_t size); +int qemu_mprotect_none(void *addr, size_t size); + +#endif diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index d1660d67fa..7bcce3bceb 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -401,112 +401,6 @@ static inline void qemu_cleanup_generic_vfree(void *p) */ #define QEMU_AUTO_VFREE __attribute__((cleanup(qemu_cleanup_generic_vfree))) -/* - * Abstraction of PROT_ and MAP_ flags as passed to mmap(), for example, - * consumed by qemu_ram_mmap(). - */ - -/* Map PROT_READ instead of PROT_READ | PROT_WRITE. */ -#define QEMU_MAP_READONLY (1 << 0) - -/* Use MAP_SHARED instead of MAP_PRIVATE. */ -#define QEMU_MAP_SHARED (1 << 1) - -/* - * Use MAP_SYNC | MAP_SHARED_VALIDATE if supported. Ignored without - * QEMU_MAP_SHARED. If mapping fails, warn and fallback to !QEMU_MAP_SYNC. - */ -#define QEMU_MAP_SYNC (1 << 2) - -/* - * Use MAP_NORESERVE to skip reservation of swap space (or huge pages if - * applicable). Bail out if not supported/effective. - */ -#define QEMU_MAP_NORESERVE (1 << 3) - - -#define QEMU_MADV_INVALID -1 - -#if defined(CONFIG_MADVISE) - -#define QEMU_MADV_WILLNEED MADV_WILLNEED -#define QEMU_MADV_DONTNEED MADV_DONTNEED -#ifdef MADV_DONTFORK -#define QEMU_MADV_DONTFORK MADV_DONTFORK -#else -#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID -#endif -#ifdef MADV_MERGEABLE -#define QEMU_MADV_MERGEABLE MADV_MERGEABLE -#else -#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID -#endif -#ifdef MADV_UNMERGEABLE -#define QEMU_MADV_UNMERGEABLE MADV_UNMERGEABLE -#else -#define QEMU_MADV_UNMERGEABLE QEMU_MADV_INVALID -#endif -#ifdef MADV_DODUMP -#define QEMU_MADV_DODUMP MADV_DODUMP -#else -#define QEMU_MADV_DODUMP QEMU_MADV_INVALID -#endif -#ifdef MADV_DONTDUMP -#define QEMU_MADV_DONTDUMP MADV_DONTDUMP -#else -#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID -#endif -#ifdef MADV_HUGEPAGE -#define QEMU_MADV_HUGEPAGE MADV_HUGEPAGE -#else -#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID -#endif -#ifdef MADV_NOHUGEPAGE -#define QEMU_MADV_NOHUGEPAGE MADV_NOHUGEPAGE -#else -#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID -#endif -#ifdef MADV_REMOVE -#define QEMU_MADV_REMOVE MADV_REMOVE -#else -#define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED -#endif -#ifdef MADV_POPULATE_WRITE -#define QEMU_MADV_POPULATE_WRITE MADV_POPULATE_WRITE -#else -#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID -#endif - -#elif defined(CONFIG_POSIX_MADVISE) - -#define QEMU_MADV_WILLNEED POSIX_MADV_WILLNEED -#define QEMU_MADV_DONTNEED POSIX_MADV_DONTNEED -#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID -#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID -#define QEMU_MADV_UNMERGEABLE QEMU_MADV_INVALID -#define QEMU_MADV_DODUMP QEMU_MADV_INVALID -#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID -#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID -#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID -#define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED -#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID - -#else /* no-op */ - -#define QEMU_MADV_WILLNEED QEMU_MADV_INVALID -#define QEMU_MADV_DONTNEED QEMU_MADV_INVALID -#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID -#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID -#define QEMU_MADV_UNMERGEABLE QEMU_MADV_INVALID -#define QEMU_MADV_DODUMP QEMU_MADV_INVALID -#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID -#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID -#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID -#define QEMU_MADV_REMOVE QEMU_MADV_INVALID -#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID - -#endif - #ifdef _WIN32 #define HAVE_CHARDEV_SERIAL 1 #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ @@ -577,11 +471,6 @@ void sigaction_invoke(struct sigaction *action, struct qemu_signalfd_siginfo *info); #endif -int qemu_madvise(void *addr, size_t len, int advice); -int qemu_mprotect_rw(void *addr, size_t size); -int qemu_mprotect_rwx(void *addr, size_t size); -int qemu_mprotect_none(void *addr, size_t size); - /* * Don't introduce new usage of this function, prefer the following * qemu_open/qemu_create that take an "Error **errp" @@ -645,22 +534,6 @@ static inline void qemu_timersub(const struct timeval *val1, void qemu_set_cloexec(int fd); -/* Starting on QEMU 2.5, qemu_hw_version() returns "2.5+" by default - * instead of QEMU_VERSION, so setting hw_version on MachineClass - * is no longer mandatory. - * - * Do NOT change this string, or it will break compatibility on all - * machine classes that don't set hw_version. - */ -#define QEMU_HW_VERSION "2.5+" - -/* QEMU "hardware version" setting. Used to replace code that exposed - * QEMU_VERSION to guests in the past and need to keep compatibility. - * Do not use qemu_hw_version() in new code. - */ -void qemu_set_hw_version(const char *); -const char *qemu_hw_version(void); - void fips_set_state(bool requested); bool fips_get_state(void); @@ -727,11 +600,6 @@ pid_t qemu_fork(Error **errp); extern uintptr_t qemu_real_host_page_size; extern intptr_t qemu_real_host_page_mask; -extern int qemu_icache_linesize; -extern int qemu_icache_linesize_log; -extern int qemu_dcache_linesize; -extern int qemu_dcache_linesize_log; - /* * After using getopt or getopt_long, if you need to parse another set * of options, then you must reset optind. Unfortunately the way to @@ -805,6 +673,19 @@ static inline int platform_does_not_support_system(const char *command) } #endif /* !HAVE_SYSTEM_FUNCTION */ +/** + * Duplicate directory entry @dent. + * + * It is highly recommended to use this function instead of open coding + * duplication of @c dirent objects, because the actual @c struct @c dirent + * size may be bigger or shorter than @c sizeof(struct dirent) and correct + * handling is platform specific (see gitlab issue #841). + * + * @dent - original directory entry to be duplicated + * @returns duplicated directory entry which should be freed with g_free() + */ +struct dirent *qemu_dirent_dup(struct dirent *dent); + #ifdef __cplusplus } #endif diff --git a/include/standard-headers/asm-x86/kvm_para.h b/include/standard-headers/asm-x86/kvm_para.h index 204cfb8640..f0235e58a1 100644 --- a/include/standard-headers/asm-x86/kvm_para.h +++ b/include/standard-headers/asm-x86/kvm_para.h @@ -8,6 +8,7 @@ * should be used to determine that a VM is running under KVM. */ #define KVM_CPUID_SIGNATURE 0x40000000 +#define KVM_SIGNATURE "KVMKVMKVM\0\0\0" /* This CPUID returns two feature bitmaps in eax, edx. Before enabling * a particular paravirtualization, the appropriate feature bit should diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h index 2c025cb4fe..4888f85f69 100644 --- a/include/standard-headers/drm/drm_fourcc.h +++ b/include/standard-headers/drm/drm_fourcc.h @@ -313,6 +313,13 @@ extern "C" { */ #define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ +/* 2 plane YCbCr420. + * 3 10 bit components and 2 padding bits packed into 4 bytes. + * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian + * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian + */ +#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */ + /* 3 plane non-subsampled (444) YCbCr * 16 bits per component, but only 10 bits are used and 6 bits are padded * index 0: Y plane, [15:0] Y:x [10:6] little endian @@ -853,6 +860,10 @@ drm_fourcc_canonicalize_nvidia_format_mod(uint64_t modifier) * and UV. Some SAND-using hardware stores UV in a separate tiled * image from Y to reduce the column height, which is not supported * with these modifiers. + * + * The DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT modifier is also + * supported for DRM_FORMAT_P030 where the columns remain as 128 bytes + * wide, but as this is a 10 bpp format that translates to 96 pixels. */ #define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \ diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h index 688eb8dc39..38d5a4cd6e 100644 --- a/include/standard-headers/linux/ethtool.h +++ b/include/standard-headers/linux/ethtool.h @@ -231,6 +231,7 @@ enum tunable_id { ETHTOOL_RX_COPYBREAK, ETHTOOL_TX_COPYBREAK, ETHTOOL_PFC_PREVENTION_TOUT, /* timeout in msecs */ + ETHTOOL_TX_COPYBREAK_BUF_SIZE, /* * Add your fresh new tunable attribute above and remember to update * tunable_strings[] in net/ethtool/common.c diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h index 23ea31708b..bda06258be 100644 --- a/include/standard-headers/linux/fuse.h +++ b/include/standard-headers/linux/fuse.h @@ -184,6 +184,16 @@ * * 7.34 * - add FUSE_SYNCFS + * + * 7.35 + * - add FOPEN_NOFLUSH + * + * 7.36 + * - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag + * - add flags2 to fuse_init_in and fuse_init_out + * - add FUSE_SECURITY_CTX init flag + * - add security context to create, mkdir, symlink, and mknod requests + * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX */ #ifndef _LINUX_FUSE_H @@ -215,7 +225,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 34 +#define FUSE_KERNEL_MINOR_VERSION 36 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -286,12 +296,14 @@ struct fuse_file_lock { * FOPEN_NONSEEKABLE: the file is not seekable * FOPEN_CACHE_DIR: allow caching this directory * FOPEN_STREAM: the file is stream-like (no file position at all) + * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE) */ #define FOPEN_DIRECT_IO (1 << 0) #define FOPEN_KEEP_CACHE (1 << 1) #define FOPEN_NONSEEKABLE (1 << 2) #define FOPEN_CACHE_DIR (1 << 3) #define FOPEN_STREAM (1 << 4) +#define FOPEN_NOFLUSH (1 << 5) /** * INIT request/reply flags @@ -332,6 +344,11 @@ struct fuse_file_lock { * write/truncate sgid is killed only if file has group * execute permission. (Same as Linux VFS behavior). * FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in + * FUSE_INIT_EXT: extended fuse_init_in request + * FUSE_INIT_RESERVED: reserved, do not use + * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and + * mknod + * FUSE_HAS_INODE_DAX: use per inode DAX */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -363,6 +380,11 @@ struct fuse_file_lock { #define FUSE_SUBMOUNTS (1 << 27) #define FUSE_HANDLE_KILLPRIV_V2 (1 << 28) #define FUSE_SETXATTR_EXT (1 << 29) +#define FUSE_INIT_EXT (1 << 30) +#define FUSE_INIT_RESERVED (1 << 31) +/* bits 32..63 get shifted down 32 bits into the flags2 field */ +#define FUSE_SECURITY_CTX (1ULL << 32) +#define FUSE_HAS_INODE_DAX (1ULL << 33) /** * CUSE INIT request/reply flags @@ -445,8 +467,10 @@ struct fuse_file_lock { * fuse_attr flags * * FUSE_ATTR_SUBMOUNT: Object is a submount root + * FUSE_ATTR_DAX: Enable DAX for this file in per inode DAX mode */ #define FUSE_ATTR_SUBMOUNT (1 << 0) +#define FUSE_ATTR_DAX (1 << 1) /** * Open flags @@ -732,6 +756,8 @@ struct fuse_init_in { uint32_t minor; uint32_t max_readahead; uint32_t flags; + uint32_t flags2; + uint32_t unused[11]; }; #define FUSE_COMPAT_INIT_OUT_SIZE 8 @@ -748,7 +774,8 @@ struct fuse_init_out { uint32_t time_gran; uint16_t max_pages; uint16_t map_alignment; - uint32_t unused[8]; + uint32_t flags2; + uint32_t unused[7]; }; #define CUSE_INIT_INFO_MAX 4096 @@ -856,9 +883,12 @@ struct fuse_dirent { char name[]; }; -#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) -#define FUSE_DIRENT_ALIGN(x) \ +/* Align variable length records to 64bit boundary */ +#define FUSE_REC_ALIGN(x) \ (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) + +#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) +#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x) #define FUSE_DIRENT_SIZE(d) \ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) @@ -975,4 +1005,26 @@ struct fuse_syncfs_in { uint64_t padding; }; +/* + * For each security context, send fuse_secctx with size of security context + * fuse_secctx will be followed by security context name and this in turn + * will be followed by actual context label. + * fuse_secctx, name, context + */ +struct fuse_secctx { + uint32_t size; + uint32_t padding; +}; + +/* + * Contains the information about how many fuse_secctx structures are being + * sent and what's the total size of all security contexts (including + * size of fuse_secctx_header). + * + */ +struct fuse_secctx_header { + uint32_t size; + uint32_t nr_secctx; +}; + #endif /* _LINUX_FUSE_H */ diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index ff6ccbc6ef..bee1a9ed6e 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -301,23 +301,23 @@ #define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ #define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ -/* Message Signalled Interrupt registers */ +/* Message Signaled Interrupt registers */ -#define PCI_MSI_FLAGS 2 /* Message Control */ +#define PCI_MSI_FLAGS 0x02 /* Message Control */ #define PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */ #define PCI_MSI_FLAGS_QMASK 0x000e /* Maximum queue size available */ #define PCI_MSI_FLAGS_QSIZE 0x0070 /* Message queue size configured */ #define PCI_MSI_FLAGS_64BIT 0x0080 /* 64-bit addresses allowed */ #define PCI_MSI_FLAGS_MASKBIT 0x0100 /* Per-vector masking capable */ #define PCI_MSI_RFU 3 /* Rest of capability flags */ -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ -#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ -#define PCI_MSI_PENDING_32 16 /* Pending intrs for 32-bit devices */ -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ -#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ -#define PCI_MSI_PENDING_64 20 /* Pending intrs for 64-bit devices */ +#define PCI_MSI_ADDRESS_LO 0x04 /* Lower 32 bits */ +#define PCI_MSI_ADDRESS_HI 0x08 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ +#define PCI_MSI_DATA_32 0x08 /* 16 bits of data for 32-bit devices */ +#define PCI_MSI_MASK_32 0x0c /* Mask bits register for 32-bit devices */ +#define PCI_MSI_PENDING_32 0x10 /* Pending intrs for 32-bit devices */ +#define PCI_MSI_DATA_64 0x0c /* 16 bits of data for 64-bit devices */ +#define PCI_MSI_MASK_64 0x10 /* Mask bits register for 64-bit devices */ +#define PCI_MSI_PENDING_64 0x14 /* Pending intrs for 64-bit devices */ /* MSI-X registers (in MSI-X capability) */ #define PCI_MSIX_FLAGS 2 /* Message Control */ @@ -335,10 +335,10 @@ /* MSI-X Table entry format (in memory mapped by a BAR) */ #define PCI_MSIX_ENTRY_SIZE 16 -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 /* Message Address */ -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 /* Message Upper Address */ -#define PCI_MSIX_ENTRY_DATA 8 /* Message Data */ -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 /* Vector Control */ +#define PCI_MSIX_ENTRY_LOWER_ADDR 0x0 /* Message Address */ +#define PCI_MSIX_ENTRY_UPPER_ADDR 0x4 /* Message Upper Address */ +#define PCI_MSIX_ENTRY_DATA 0x8 /* Message Data */ +#define PCI_MSIX_ENTRY_VECTOR_CTRL 0xc /* Vector Control */ #define PCI_MSIX_ENTRY_CTRL_MASKBIT 0x00000001 /* CompactPCI Hotswap Register */ @@ -470,7 +470,7 @@ /* PCI Express capability registers */ -#define PCI_EXP_FLAGS 2 /* Capabilities register */ +#define PCI_EXP_FLAGS 0x02 /* Capabilities register */ #define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ #define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ #define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ @@ -484,7 +484,7 @@ #define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ #define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ #define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ -#define PCI_EXP_DEVCAP 4 /* Device capabilities */ +#define PCI_EXP_DEVCAP 0x04 /* Device capabilities */ #define PCI_EXP_DEVCAP_PAYLOAD 0x00000007 /* Max_Payload_Size */ #define PCI_EXP_DEVCAP_PHANTOM 0x00000018 /* Phantom functions */ #define PCI_EXP_DEVCAP_EXT_TAG 0x00000020 /* Extended tags */ @@ -497,7 +497,7 @@ #define PCI_EXP_DEVCAP_PWR_VAL 0x03fc0000 /* Slot Power Limit Value */ #define PCI_EXP_DEVCAP_PWR_SCL 0x0c000000 /* Slot Power Limit Scale */ #define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ -#define PCI_EXP_DEVCTL 8 /* Device Control */ +#define PCI_EXP_DEVCTL 0x08 /* Device Control */ #define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ #define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ #define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ @@ -522,7 +522,7 @@ #define PCI_EXP_DEVCTL_READRQ_2048B 0x4000 /* 2048 Bytes */ #define PCI_EXP_DEVCTL_READRQ_4096B 0x5000 /* 4096 Bytes */ #define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ -#define PCI_EXP_DEVSTA 10 /* Device Status */ +#define PCI_EXP_DEVSTA 0x0a /* Device Status */ #define PCI_EXP_DEVSTA_CED 0x0001 /* Correctable Error Detected */ #define PCI_EXP_DEVSTA_NFED 0x0002 /* Non-Fatal Error Detected */ #define PCI_EXP_DEVSTA_FED 0x0004 /* Fatal Error Detected */ @@ -530,7 +530,7 @@ #define PCI_EXP_DEVSTA_AUXPD 0x0010 /* AUX Power Detected */ #define PCI_EXP_DEVSTA_TRPND 0x0020 /* Transactions Pending */ #define PCI_CAP_EXP_RC_ENDPOINT_SIZEOF_V1 12 /* v1 endpoints without link end here */ -#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ +#define PCI_EXP_LNKCAP 0x0c /* Link Capabilities */ #define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ #define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */ #define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */ @@ -549,7 +549,7 @@ #define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ #define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ #define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ -#define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL 0x10 /* Link Control */ #define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ #define PCI_EXP_LNKCTL_ASPM_L0S 0x0001 /* L0s Enable */ #define PCI_EXP_LNKCTL_ASPM_L1 0x0002 /* L1 Enable */ @@ -562,7 +562,7 @@ #define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ #define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ #define PCI_EXP_LNKCTL_LABIE 0x0800 /* Link Autonomous Bandwidth Interrupt Enable */ -#define PCI_EXP_LNKSTA 18 /* Link Status */ +#define PCI_EXP_LNKSTA 0x12 /* Link Status */ #define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ #define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001 /* Current Link Speed 2.5GT/s */ #define PCI_EXP_LNKSTA_CLS_5_0GB 0x0002 /* Current Link Speed 5.0GT/s */ @@ -582,7 +582,7 @@ #define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ #define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V1 20 /* v1 endpoints with link end here */ -#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ +#define PCI_EXP_SLTCAP 0x14 /* Slot Capabilities */ #define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ #define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ #define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ @@ -595,7 +595,7 @@ #define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ #define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ #define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ -#define PCI_EXP_SLTCTL 24 /* Slot Control */ +#define PCI_EXP_SLTCTL 0x18 /* Slot Control */ #define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ #define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ #define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ @@ -617,7 +617,7 @@ #define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ #define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ #define PCI_EXP_SLTCTL_IBPD_DISABLE 0x4000 /* In-band PD disable */ -#define PCI_EXP_SLTSTA 26 /* Slot Status */ +#define PCI_EXP_SLTSTA 0x1a /* Slot Status */ #define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ #define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ #define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ @@ -627,15 +627,15 @@ #define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ #define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ #define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ -#define PCI_EXP_RTCTL 28 /* Root Control */ +#define PCI_EXP_RTCTL 0x1c /* Root Control */ #define PCI_EXP_RTCTL_SECEE 0x0001 /* System Error on Correctable Error */ #define PCI_EXP_RTCTL_SENFEE 0x0002 /* System Error on Non-Fatal Error */ #define PCI_EXP_RTCTL_SEFEE 0x0004 /* System Error on Fatal Error */ #define PCI_EXP_RTCTL_PMEIE 0x0008 /* PME Interrupt Enable */ #define PCI_EXP_RTCTL_CRSSVE 0x0010 /* CRS Software Visibility Enable */ -#define PCI_EXP_RTCAP 30 /* Root Capabilities */ +#define PCI_EXP_RTCAP 0x1e /* Root Capabilities */ #define PCI_EXP_RTCAP_CRSVIS 0x0001 /* CRS Software Visibility capability */ -#define PCI_EXP_RTSTA 32 /* Root Status */ +#define PCI_EXP_RTSTA 0x20 /* Root Status */ #define PCI_EXP_RTSTA_PME 0x00010000 /* PME status */ #define PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */ /* @@ -646,7 +646,7 @@ * Use pcie_capability_read_word() and similar interfaces to use them * safely. */ -#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ +#define PCI_EXP_DEVCAP2 0x24 /* Device Capabilities 2 */ #define PCI_EXP_DEVCAP2_COMP_TMOUT_DIS 0x00000010 /* Completion Timeout Disable supported */ #define PCI_EXP_DEVCAP2_ARI 0x00000020 /* Alternative Routing-ID */ #define PCI_EXP_DEVCAP2_ATOMIC_ROUTE 0x00000040 /* Atomic Op routing */ @@ -658,7 +658,7 @@ #define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ #define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */ #define PCI_EXP_DEVCAP2_EE_PREFIX 0x00200000 /* End-End TLP Prefix */ -#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ +#define PCI_EXP_DEVCTL2 0x28 /* Device Control 2 */ #define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ #define PCI_EXP_DEVCTL2_COMP_TMOUT_DIS 0x0010 /* Completion Timeout Disable */ #define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ @@ -670,9 +670,9 @@ #define PCI_EXP_DEVCTL2_OBFF_MSGA_EN 0x2000 /* Enable OBFF Message type A */ #define PCI_EXP_DEVCTL2_OBFF_MSGB_EN 0x4000 /* Enable OBFF Message type B */ #define PCI_EXP_DEVCTL2_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ -#define PCI_EXP_DEVSTA2 42 /* Device Status 2 */ -#define PCI_CAP_EXP_RC_ENDPOINT_SIZEOF_V2 44 /* v2 endpoints without link end here */ -#define PCI_EXP_LNKCAP2 44 /* Link Capabilities 2 */ +#define PCI_EXP_DEVSTA2 0x2a /* Device Status 2 */ +#define PCI_CAP_EXP_RC_ENDPOINT_SIZEOF_V2 0x2c /* end of v2 EPs w/o link */ +#define PCI_EXP_LNKCAP2 0x2c /* Link Capabilities 2 */ #define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002 /* Supported Speed 2.5GT/s */ #define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5GT/s */ #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */ @@ -680,7 +680,7 @@ #define PCI_EXP_LNKCAP2_SLS_32_0GB 0x00000020 /* Supported Speed 32GT/s */ #define PCI_EXP_LNKCAP2_SLS_64_0GB 0x00000040 /* Supported Speed 64GT/s */ #define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */ -#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ +#define PCI_EXP_LNKCTL2 0x30 /* Link Control 2 */ #define PCI_EXP_LNKCTL2_TLS 0x000f #define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Supported Speed 2.5GT/s */ #define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */ @@ -691,12 +691,12 @@ #define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */ #define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */ #define PCI_EXP_LNKCTL2_HASD 0x0020 /* HW Autonomous Speed Disable */ -#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */ -#define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */ +#define PCI_EXP_LNKSTA2 0x32 /* Link Status 2 */ +#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x32 /* end of v2 EPs w/ link */ +#define PCI_EXP_SLTCAP2 0x34 /* Slot Capabilities 2 */ #define PCI_EXP_SLTCAP2_IBPD 0x00000001 /* In-band PD Disable Supported */ -#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ -#define PCI_EXP_SLTSTA2 58 /* Slot Status 2 */ +#define PCI_EXP_SLTCTL2 0x38 /* Slot Control 2 */ +#define PCI_EXP_SLTSTA2 0x3a /* Slot Status 2 */ /* Extended Capabilities (PCI-X 2.0 and Express) */ #define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) @@ -742,7 +742,7 @@ #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 /* Advanced Error Reporting */ -#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ +#define PCI_ERR_UNCOR_STATUS 0x04 /* Uncorrectable Error Status */ #define PCI_ERR_UNC_UND 0x00000001 /* Undefined */ #define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ #define PCI_ERR_UNC_SURPDN 0x00000020 /* Surprise Down */ @@ -760,11 +760,11 @@ #define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC blocked TLP */ #define PCI_ERR_UNC_ATOMEG 0x01000000 /* Atomic egress blocked */ #define PCI_ERR_UNC_TLPPRE 0x02000000 /* TLP prefix blocked */ -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ +#define PCI_ERR_UNCOR_MASK 0x08 /* Uncorrectable Error Mask */ /* Same bits as above */ -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ +#define PCI_ERR_UNCOR_SEVER 0x0c /* Uncorrectable Error Severity */ /* Same bits as above */ -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ +#define PCI_ERR_COR_STATUS 0x10 /* Correctable Error Status */ #define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ #define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ #define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ @@ -773,20 +773,20 @@ #define PCI_ERR_COR_ADV_NFAT 0x00002000 /* Advisory Non-Fatal */ #define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ #define PCI_ERR_COR_LOG_OVER 0x00008000 /* Header Log Overflow */ -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ +#define PCI_ERR_COR_MASK 0x14 /* Correctable Error Mask */ /* Same bits as above */ -#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ +#define PCI_ERR_CAP 0x18 /* Advanced Error Capabilities & Ctrl*/ +#define PCI_ERR_CAP_FEP(x) ((x) & 0x1f) /* First Error Pointer */ #define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ #define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ #define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ #define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ -#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ -#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ +#define PCI_ERR_HEADER_LOG 0x1c /* Header Log Register (16 bytes) */ +#define PCI_ERR_ROOT_COMMAND 0x2c /* Root Error Command */ #define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 /* Correctable Err Reporting Enable */ #define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 /* Non-Fatal Err Reporting Enable */ #define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 /* Fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_STATUS 48 +#define PCI_ERR_ROOT_STATUS 0x30 #define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ #define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 /* Multiple ERR_COR */ #define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 /* ERR_FATAL/NONFATAL */ @@ -795,52 +795,52 @@ #define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ #define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ #define PCI_ERR_ROOT_AER_IRQ 0xf8000000 /* Advanced Error Interrupt Message Number */ -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ +#define PCI_ERR_ROOT_ERR_SRC 0x34 /* Error Source Identification */ /* Virtual Channel */ -#define PCI_VC_PORT_CAP1 4 +#define PCI_VC_PORT_CAP1 0x04 #define PCI_VC_CAP1_EVCC 0x00000007 /* extended VC count */ #define PCI_VC_CAP1_LPEVCC 0x00000070 /* low prio extended VC count */ #define PCI_VC_CAP1_ARB_SIZE 0x00000c00 -#define PCI_VC_PORT_CAP2 8 +#define PCI_VC_PORT_CAP2 0x08 #define PCI_VC_CAP2_32_PHASE 0x00000002 #define PCI_VC_CAP2_64_PHASE 0x00000004 #define PCI_VC_CAP2_128_PHASE 0x00000008 #define PCI_VC_CAP2_ARB_OFF 0xff000000 -#define PCI_VC_PORT_CTRL 12 +#define PCI_VC_PORT_CTRL 0x0c #define PCI_VC_PORT_CTRL_LOAD_TABLE 0x00000001 -#define PCI_VC_PORT_STATUS 14 +#define PCI_VC_PORT_STATUS 0x0e #define PCI_VC_PORT_STATUS_TABLE 0x00000001 -#define PCI_VC_RES_CAP 16 +#define PCI_VC_RES_CAP 0x10 #define PCI_VC_RES_CAP_32_PHASE 0x00000002 #define PCI_VC_RES_CAP_64_PHASE 0x00000004 #define PCI_VC_RES_CAP_128_PHASE 0x00000008 #define PCI_VC_RES_CAP_128_PHASE_TB 0x00000010 #define PCI_VC_RES_CAP_256_PHASE 0x00000020 #define PCI_VC_RES_CAP_ARB_OFF 0xff000000 -#define PCI_VC_RES_CTRL 20 +#define PCI_VC_RES_CTRL 0x14 #define PCI_VC_RES_CTRL_LOAD_TABLE 0x00010000 #define PCI_VC_RES_CTRL_ARB_SELECT 0x000e0000 #define PCI_VC_RES_CTRL_ID 0x07000000 #define PCI_VC_RES_CTRL_ENABLE 0x80000000 -#define PCI_VC_RES_STATUS 26 +#define PCI_VC_RES_STATUS 0x1a #define PCI_VC_RES_STATUS_TABLE 0x00000001 #define PCI_VC_RES_STATUS_NEGO 0x00000002 #define PCI_CAP_VC_BASE_SIZEOF 0x10 -#define PCI_CAP_VC_PER_VC_SIZEOF 0x0C +#define PCI_CAP_VC_PER_VC_SIZEOF 0x0c /* Power Budgeting */ -#define PCI_PWR_DSR 4 /* Data Select Register */ -#define PCI_PWR_DATA 8 /* Data Register */ +#define PCI_PWR_DSR 0x04 /* Data Select Register */ +#define PCI_PWR_DATA 0x08 /* Data Register */ #define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ #define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ #define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ #define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ #define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ #define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ -#define PCI_PWR_CAP 12 /* Capability */ +#define PCI_PWR_CAP 0x0c /* Capability */ #define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ -#define PCI_EXT_CAP_PWR_SIZEOF 16 +#define PCI_EXT_CAP_PWR_SIZEOF 0x10 /* Root Complex Event Collector Endpoint Association */ #define PCI_RCEC_RCIEP_BITMAP 4 /* Associated Bitmap for RCiEPs */ @@ -964,7 +964,7 @@ #define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ #define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ #define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ -#define PCI_EXT_CAP_SRIOV_SIZEOF 64 +#define PCI_EXT_CAP_SRIOV_SIZEOF 0x40 #define PCI_LTR_MAX_SNOOP_LAT 0x4 #define PCI_LTR_MAX_NOSNOOP_LAT 0x6 @@ -1017,12 +1017,12 @@ #define PCI_TPH_LOC_NONE 0x000 /* no location */ #define PCI_TPH_LOC_CAP 0x200 /* in capability */ #define PCI_TPH_LOC_MSIX 0x400 /* in MSI-X */ -#define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* st table mask */ -#define PCI_TPH_CAP_ST_SHIFT 16 /* st table shift */ -#define PCI_TPH_BASE_SIZEOF 12 /* size with no st table */ +#define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* ST table mask */ +#define PCI_TPH_CAP_ST_SHIFT 16 /* ST table shift */ +#define PCI_TPH_BASE_SIZEOF 0xc /* size with no ST table */ /* Downstream Port Containment */ -#define PCI_EXP_DPC_CAP 4 /* DPC Capability */ +#define PCI_EXP_DPC_CAP 0x04 /* DPC Capability */ #define PCI_EXP_DPC_IRQ 0x001F /* Interrupt Message Number */ #define PCI_EXP_DPC_CAP_RP_EXT 0x0020 /* Root Port Extensions */ #define PCI_EXP_DPC_CAP_POISONED_TLP 0x0040 /* Poisoned TLP Egress Blocking Supported */ @@ -1030,19 +1030,19 @@ #define PCI_EXP_DPC_RP_PIO_LOG_SIZE 0x0F00 /* RP PIO Log Size */ #define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */ -#define PCI_EXP_DPC_CTL 6 /* DPC control */ +#define PCI_EXP_DPC_CTL 0x06 /* DPC control */ #define PCI_EXP_DPC_CTL_EN_FATAL 0x0001 /* Enable trigger on ERR_FATAL message */ #define PCI_EXP_DPC_CTL_EN_NONFATAL 0x0002 /* Enable trigger on ERR_NONFATAL message */ #define PCI_EXP_DPC_CTL_INT_EN 0x0008 /* DPC Interrupt Enable */ -#define PCI_EXP_DPC_STATUS 8 /* DPC Status */ +#define PCI_EXP_DPC_STATUS 0x08 /* DPC Status */ #define PCI_EXP_DPC_STATUS_TRIGGER 0x0001 /* Trigger Status */ #define PCI_EXP_DPC_STATUS_TRIGGER_RSN 0x0006 /* Trigger Reason */ #define PCI_EXP_DPC_STATUS_INTERRUPT 0x0008 /* Interrupt Status */ #define PCI_EXP_DPC_RP_BUSY 0x0010 /* Root Port Busy */ #define PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT 0x0060 /* Trig Reason Extension */ -#define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */ +#define PCI_EXP_DPC_SOURCE_ID 0x0A /* DPC Source Identifier */ #define PCI_EXP_DPC_RP_PIO_STATUS 0x0C /* RP PIO Status */ #define PCI_EXP_DPC_RP_PIO_MASK 0x10 /* RP PIO Mask */ @@ -1086,7 +1086,11 @@ /* Designated Vendor-Specific (DVSEC, PCI_EXT_CAP_ID_DVSEC) */ #define PCI_DVSEC_HEADER1 0x4 /* Designated Vendor-Specific Header1 */ +#define PCI_DVSEC_HEADER1_VID(x) ((x) & 0xffff) +#define PCI_DVSEC_HEADER1_REV(x) (((x) >> 16) & 0xf) +#define PCI_DVSEC_HEADER1_LEN(x) (((x) >> 20) & 0xfff) #define PCI_DVSEC_HEADER2 0x8 /* Designated Vendor-Specific Header2 */ +#define PCI_DVSEC_HEADER2_ID(x) ((x) & 0xffff) /* Data Link Feature */ #define PCI_DLF_CAP 0x04 /* Capabilities Register */ diff --git a/include/standard-headers/linux/virtio_gpio.h b/include/standard-headers/linux/virtio_gpio.h new file mode 100644 index 0000000000..2b5cf06349 --- /dev/null +++ b/include/standard-headers/linux/virtio_gpio.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef _LINUX_VIRTIO_GPIO_H +#define _LINUX_VIRTIO_GPIO_H + +#include "standard-headers/linux/types.h" + +/* Virtio GPIO Feature bits */ +#define VIRTIO_GPIO_F_IRQ 0 + +/* Virtio GPIO request types */ +#define VIRTIO_GPIO_MSG_GET_NAMES 0x0001 +#define VIRTIO_GPIO_MSG_GET_DIRECTION 0x0002 +#define VIRTIO_GPIO_MSG_SET_DIRECTION 0x0003 +#define VIRTIO_GPIO_MSG_GET_VALUE 0x0004 +#define VIRTIO_GPIO_MSG_SET_VALUE 0x0005 +#define VIRTIO_GPIO_MSG_IRQ_TYPE 0x0006 + +/* Possible values of the status field */ +#define VIRTIO_GPIO_STATUS_OK 0x0 +#define VIRTIO_GPIO_STATUS_ERR 0x1 + +/* Direction types */ +#define VIRTIO_GPIO_DIRECTION_NONE 0x00 +#define VIRTIO_GPIO_DIRECTION_OUT 0x01 +#define VIRTIO_GPIO_DIRECTION_IN 0x02 + +/* Virtio GPIO IRQ types */ +#define VIRTIO_GPIO_IRQ_TYPE_NONE 0x00 +#define VIRTIO_GPIO_IRQ_TYPE_EDGE_RISING 0x01 +#define VIRTIO_GPIO_IRQ_TYPE_EDGE_FALLING 0x02 +#define VIRTIO_GPIO_IRQ_TYPE_EDGE_BOTH 0x03 +#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH 0x04 +#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW 0x08 + +struct virtio_gpio_config { + uint16_t ngpio; + uint8_t padding[2]; + uint32_t gpio_names_size; +}; + +/* Virtio GPIO Request / Response */ +struct virtio_gpio_request { + uint16_t type; + uint16_t gpio; + uint32_t value; +}; + +struct virtio_gpio_response { + uint8_t status; + uint8_t value; +}; + +struct virtio_gpio_response_get_names { + uint8_t status; + uint8_t value[]; +}; + +/* Virtio GPIO IRQ Request / Response */ +struct virtio_gpio_irq_request { + uint16_t gpio; +}; + +struct virtio_gpio_irq_response { + uint8_t status; +}; + +/* Possible values of the interrupt status field */ +#define VIRTIO_GPIO_IRQ_STATUS_INVALID 0x0 +#define VIRTIO_GPIO_IRQ_STATUS_VALID 0x1 + +#endif /* _LINUX_VIRTIO_GPIO_H */ diff --git a/include/standard-headers/linux/virtio_i2c.h b/include/standard-headers/linux/virtio_i2c.h new file mode 100644 index 0000000000..09fa907793 --- /dev/null +++ b/include/standard-headers/linux/virtio_i2c.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* + * Definitions for virtio I2C Adpter + * + * Copyright (c) 2021 Intel Corporation. All rights reserved. + */ + +#ifndef _LINUX_VIRTIO_I2C_H +#define _LINUX_VIRTIO_I2C_H + +#include "standard-headers/linux/const.h" +#include "standard-headers/linux/types.h" + +/* Virtio I2C Feature bits */ +#define VIRTIO_I2C_F_ZERO_LENGTH_REQUEST 0 + +/* The bit 0 of the @virtio_i2c_out_hdr.@flags, used to group the requests */ +#define VIRTIO_I2C_FLAGS_FAIL_NEXT _BITUL(0) + +/* The bit 1 of the @virtio_i2c_out_hdr.@flags, used to mark a buffer as read */ +#define VIRTIO_I2C_FLAGS_M_RD _BITUL(1) + +/** + * struct virtio_i2c_out_hdr - the virtio I2C message OUT header + * @addr: the controlled device address + * @padding: used to pad to full dword + * @flags: used for feature extensibility + */ +struct virtio_i2c_out_hdr { + uint16_t addr; + uint16_t padding; + uint32_t flags; +}; + +/** + * struct virtio_i2c_in_hdr - the virtio I2C message IN header + * @status: the processing result from the backend + */ +struct virtio_i2c_in_hdr { + uint8_t status; +}; + +/* The final status written by the device */ +#define VIRTIO_I2C_MSG_OK 0 +#define VIRTIO_I2C_MSG_ERR 1 + +#endif /* _LINUX_VIRTIO_I2C_H */ diff --git a/include/standard-headers/linux/virtio_iommu.h b/include/standard-headers/linux/virtio_iommu.h index b9443b83a1..366379c2f0 100644 --- a/include/standard-headers/linux/virtio_iommu.h +++ b/include/standard-headers/linux/virtio_iommu.h @@ -16,6 +16,7 @@ #define VIRTIO_IOMMU_F_BYPASS 3 #define VIRTIO_IOMMU_F_PROBE 4 #define VIRTIO_IOMMU_F_MMIO 5 +#define VIRTIO_IOMMU_F_BYPASS_CONFIG 6 struct virtio_iommu_range_64 { uint64_t start; @@ -36,6 +37,8 @@ struct virtio_iommu_config { struct virtio_iommu_range_32 domain_range; /* Probe buffer size */ uint32_t probe_size; + uint8_t bypass; + uint8_t reserved[3]; }; /* Request types */ @@ -66,11 +69,14 @@ struct virtio_iommu_req_tail { uint8_t reserved[3]; }; +#define VIRTIO_IOMMU_ATTACH_F_BYPASS (1 << 0) + struct virtio_iommu_req_attach { struct virtio_iommu_req_head head; uint32_t domain; uint32_t endpoint; - uint8_t reserved[8]; + uint32_t flags; + uint8_t reserved[4]; struct virtio_iommu_req_tail tail; }; diff --git a/include/standard-headers/linux/virtio_pcidev.h b/include/standard-headers/linux/virtio_pcidev.h new file mode 100644 index 0000000000..bdf1d062da --- /dev/null +++ b/include/standard-headers/linux/virtio_pcidev.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * Copyright (C) 2021 Intel Corporation + * Author: Johannes Berg + */ +#ifndef _LINUX_VIRTIO_PCIDEV_H +#define _LINUX_VIRTIO_PCIDEV_H +#include "standard-headers/linux/types.h" + +/** + * enum virtio_pcidev_ops - virtual PCI device operations + * @VIRTIO_PCIDEV_OP_RESERVED: reserved to catch errors + * @VIRTIO_PCIDEV_OP_CFG_READ: read config space, size is 1, 2, 4 or 8; + * the @data field should be filled in by the device (in little endian). + * @VIRTIO_PCIDEV_OP_CFG_WRITE: write config space, size is 1, 2, 4 or 8; + * the @data field contains the data to write (in little endian). + * @VIRTIO_PCIDEV_OP_MMIO_READ: read BAR mem/pio, size can be variable; + * the @data field should be filled in by the device (in little endian). + * @VIRTIO_PCIDEV_OP_MMIO_WRITE: write BAR mem/pio, size can be variable; + * the @data field contains the data to write (in little endian). + * @VIRTIO_PCIDEV_OP_MMIO_MEMSET: memset MMIO, size is variable but + * the @data field only has one byte (unlike @VIRTIO_PCIDEV_OP_MMIO_WRITE) + * @VIRTIO_PCIDEV_OP_INT: legacy INTx# pin interrupt, the addr field is 1-4 for + * the number + * @VIRTIO_PCIDEV_OP_MSI: MSI(-X) interrupt, this message basically transports + * the 16- or 32-bit write that would otherwise be done into memory, + * analogous to the write messages (@VIRTIO_PCIDEV_OP_MMIO_WRITE) above + * @VIRTIO_PCIDEV_OP_PME: Dummy message whose content is ignored (and should be + * all zeroes) to signal the PME# pin. + */ +enum virtio_pcidev_ops { + VIRTIO_PCIDEV_OP_RESERVED = 0, + VIRTIO_PCIDEV_OP_CFG_READ, + VIRTIO_PCIDEV_OP_CFG_WRITE, + VIRTIO_PCIDEV_OP_MMIO_READ, + VIRTIO_PCIDEV_OP_MMIO_WRITE, + VIRTIO_PCIDEV_OP_MMIO_MEMSET, + VIRTIO_PCIDEV_OP_INT, + VIRTIO_PCIDEV_OP_MSI, + VIRTIO_PCIDEV_OP_PME, +}; + +/** + * struct virtio_pcidev_msg - virtio PCI device operation + * @op: the operation to do + * @bar: the bar (only with BAR read/write messages) + * @reserved: reserved + * @size: the size of the read/write (in bytes) + * @addr: the address to read/write + * @data: the data, normally @size long, but just one byte for + * %VIRTIO_PCIDEV_OP_MMIO_MEMSET + * + * Note: the fields are all in native (CPU) endian, however, the + * @data values will often be in little endian (see the ops above.) + */ +struct virtio_pcidev_msg { + uint8_t op; + uint8_t bar; + uint16_t reserved; + uint32_t size; + uint64_t addr; + uint8_t data[]; +}; + +#endif /* _LINUX_VIRTIO_PCIDEV_H */ diff --git a/include/standard-headers/linux/virtio_scmi.h b/include/standard-headers/linux/virtio_scmi.h new file mode 100644 index 0000000000..8f2c305aea --- /dev/null +++ b/include/standard-headers/linux/virtio_scmi.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * Copyright (C) 2020-2021 OpenSynergy GmbH + * Copyright (C) 2021 ARM Ltd. + */ + +#ifndef _LINUX_VIRTIO_SCMI_H +#define _LINUX_VIRTIO_SCMI_H + +#include "standard-headers/linux/virtio_types.h" + +/* Device implements some SCMI notifications, or delayed responses. */ +#define VIRTIO_SCMI_F_P2A_CHANNELS 0 + +/* Device implements any SCMI statistics shared memory region */ +#define VIRTIO_SCMI_F_SHARED_MEMORY 1 + +/* Virtqueues */ + +#define VIRTIO_SCMI_VQ_TX 0 /* cmdq */ +#define VIRTIO_SCMI_VQ_RX 1 /* eventq */ +#define VIRTIO_SCMI_VQ_MAX_CNT 2 + +#endif /* _LINUX_VIRTIO_SCMI_H */ diff --git a/linux-headers/asm-generic/unistd.h b/linux-headers/asm-generic/unistd.h index 4557a8b608..1c48b0ae3b 100644 --- a/linux-headers/asm-generic/unistd.h +++ b/linux-headers/asm-generic/unistd.h @@ -883,8 +883,11 @@ __SYSCALL(__NR_process_mrelease, sys_process_mrelease) #define __NR_futex_waitv 449 __SYSCALL(__NR_futex_waitv, sys_futex_waitv) +#define __NR_set_mempolicy_home_node 450 +__SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node) + #undef __NR_syscalls -#define __NR_syscalls 450 +#define __NR_syscalls 451 /* * 32 bit systems traditionally used different diff --git a/linux-headers/asm-mips/unistd_n32.h b/linux-headers/asm-mips/unistd_n32.h index 4b3e7ad1ec..1f14a6fad3 100644 --- a/linux-headers/asm-mips/unistd_n32.h +++ b/linux-headers/asm-mips/unistd_n32.h @@ -377,5 +377,7 @@ #define __NR_landlock_add_rule (__NR_Linux + 445) #define __NR_landlock_restrict_self (__NR_Linux + 446) #define __NR_process_mrelease (__NR_Linux + 448) +#define __NR_futex_waitv (__NR_Linux + 449) +#define __NR_set_mempolicy_home_node (__NR_Linux + 450) #endif /* _ASM_UNISTD_N32_H */ diff --git a/linux-headers/asm-mips/unistd_n64.h b/linux-headers/asm-mips/unistd_n64.h index 488d9298d9..e5a8ebec78 100644 --- a/linux-headers/asm-mips/unistd_n64.h +++ b/linux-headers/asm-mips/unistd_n64.h @@ -353,5 +353,7 @@ #define __NR_landlock_add_rule (__NR_Linux + 445) #define __NR_landlock_restrict_self (__NR_Linux + 446) #define __NR_process_mrelease (__NR_Linux + 448) +#define __NR_futex_waitv (__NR_Linux + 449) +#define __NR_set_mempolicy_home_node (__NR_Linux + 450) #endif /* _ASM_UNISTD_N64_H */ diff --git a/linux-headers/asm-mips/unistd_o32.h b/linux-headers/asm-mips/unistd_o32.h index f47399870a..871d57168f 100644 --- a/linux-headers/asm-mips/unistd_o32.h +++ b/linux-headers/asm-mips/unistd_o32.h @@ -423,5 +423,7 @@ #define __NR_landlock_add_rule (__NR_Linux + 445) #define __NR_landlock_restrict_self (__NR_Linux + 446) #define __NR_process_mrelease (__NR_Linux + 448) +#define __NR_futex_waitv (__NR_Linux + 449) +#define __NR_set_mempolicy_home_node (__NR_Linux + 450) #endif /* _ASM_UNISTD_O32_H */ diff --git a/linux-headers/asm-powerpc/unistd_32.h b/linux-headers/asm-powerpc/unistd_32.h index 11d54696dc..585c7fefbc 100644 --- a/linux-headers/asm-powerpc/unistd_32.h +++ b/linux-headers/asm-powerpc/unistd_32.h @@ -430,6 +430,8 @@ #define __NR_landlock_add_rule 445 #define __NR_landlock_restrict_self 446 #define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 #endif /* _ASM_UNISTD_32_H */ diff --git a/linux-headers/asm-powerpc/unistd_64.h b/linux-headers/asm-powerpc/unistd_64.h index cf740bab13..350f7ec0ac 100644 --- a/linux-headers/asm-powerpc/unistd_64.h +++ b/linux-headers/asm-powerpc/unistd_64.h @@ -402,6 +402,8 @@ #define __NR_landlock_add_rule 445 #define __NR_landlock_restrict_self 446 #define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 #endif /* _ASM_UNISTD_64_H */ diff --git a/linux-headers/asm-riscv/bitsperlong.h b/linux-headers/asm-riscv/bitsperlong.h new file mode 100644 index 0000000000..cc5c45a9ce --- /dev/null +++ b/linux-headers/asm-riscv/bitsperlong.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (C) 2012 ARM Ltd. + * Copyright (C) 2015 Regents of the University of California + */ + +#ifndef _ASM_RISCV_BITSPERLONG_H +#define _ASM_RISCV_BITSPERLONG_H + +#define __BITS_PER_LONG (__SIZEOF_POINTER__ * 8) + +#include + +#endif /* _ASM_RISCV_BITSPERLONG_H */ diff --git a/linux-headers/asm-riscv/mman.h b/linux-headers/asm-riscv/mman.h new file mode 100644 index 0000000000..8eebf89f5a --- /dev/null +++ b/linux-headers/asm-riscv/mman.h @@ -0,0 +1 @@ +#include diff --git a/linux-headers/asm-riscv/unistd.h b/linux-headers/asm-riscv/unistd.h new file mode 100644 index 0000000000..8062996c2d --- /dev/null +++ b/linux-headers/asm-riscv/unistd.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2018 David Abdurachmanov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef __LP64__ +#define __ARCH_WANT_NEW_STAT +#define __ARCH_WANT_SET_GET_RLIMIT +#endif /* __LP64__ */ + +#define __ARCH_WANT_SYS_CLONE3 + +#include + +/* + * Allows the instruction cache to be flushed from userspace. Despite RISC-V + * having a direct 'fence.i' instruction available to userspace (which we + * can't trap!), that's not actually viable when running on Linux because the + * kernel might schedule a process on another hart. There is no way for + * userspace to handle this without invoking the kernel (as it doesn't know the + * thread->hart mappings), so we've defined a RISC-V specific system call to + * flush the instruction cache. + * + * __NR_riscv_flush_icache is defined to flush the instruction cache over an + * address range, with the flush applying to either all threads or just the + * caller. We don't currently do anything with the address range, that's just + * in there for forwards compatibility. + */ +#ifndef __NR_riscv_flush_icache +#define __NR_riscv_flush_icache (__NR_arch_specific_syscall + 15) +#endif +__SYSCALL(__NR_riscv_flush_icache, sys_riscv_flush_icache) diff --git a/linux-headers/asm-s390/unistd_32.h b/linux-headers/asm-s390/unistd_32.h index 8f97d98128..8e644d65f5 100644 --- a/linux-headers/asm-s390/unistd_32.h +++ b/linux-headers/asm-s390/unistd_32.h @@ -420,5 +420,7 @@ #define __NR_landlock_add_rule 445 #define __NR_landlock_restrict_self 446 #define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 #endif /* _ASM_S390_UNISTD_32_H */ diff --git a/linux-headers/asm-s390/unistd_64.h b/linux-headers/asm-s390/unistd_64.h index 021ffc30e6..51da542fec 100644 --- a/linux-headers/asm-s390/unistd_64.h +++ b/linux-headers/asm-s390/unistd_64.h @@ -368,5 +368,7 @@ #define __NR_landlock_add_rule 445 #define __NR_landlock_restrict_self 446 #define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 #endif /* _ASM_S390_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 5a776a08f7..2da3316bb5 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -373,9 +373,23 @@ struct kvm_debugregs { __u64 reserved[9]; }; -/* for KVM_CAP_XSAVE */ +/* for KVM_CAP_XSAVE and KVM_CAP_XSAVE2 */ struct kvm_xsave { + /* + * KVM_GET_XSAVE2 and KVM_SET_XSAVE write and read as many bytes + * as are returned by KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) + * respectively, when invoked on the vm file descriptor. + * + * The size value returned by KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) + * will always be at least 4096. Currently, it is only greater + * than 4096 if a dynamic feature has been enabled with + * ``arch_prctl()``, but this may change in the future. + * + * The offsets of the state save areas in struct kvm_xsave follow + * the contents of CPUID leaf 0xD on the host. + */ __u32 region[1024]; + __u32 extra[0]; }; #define KVM_MAX_XCRS 16 diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h index 9c9ffe312b..87e1e977af 100644 --- a/linux-headers/asm-x86/unistd_32.h +++ b/linux-headers/asm-x86/unistd_32.h @@ -440,6 +440,7 @@ #define __NR_memfd_secret 447 #define __NR_process_mrelease 448 #define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 #endif /* _ASM_UNISTD_32_H */ diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h index 084f1eef9c..147a78d623 100644 --- a/linux-headers/asm-x86/unistd_64.h +++ b/linux-headers/asm-x86/unistd_64.h @@ -362,6 +362,7 @@ #define __NR_memfd_secret 447 #define __NR_process_mrelease 448 #define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 #endif /* _ASM_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h index a2441affc2..27098db7fb 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -315,6 +315,7 @@ #define __NR_memfd_secret (__X32_SYSCALL_BIT + 447) #define __NR_process_mrelease (__X32_SYSCALL_BIT + 448) #define __NR_futex_waitv (__X32_SYSCALL_BIT + 449) +#define __NR_set_mempolicy_home_node (__X32_SYSCALL_BIT + 450) #define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512) #define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513) #define __NR_ioctl (__X32_SYSCALL_BIT + 514) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 02c5e7b7bb..00af3bc333 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1130,6 +1130,9 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_BINARY_STATS_FD 203 #define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204 #define KVM_CAP_ARM_MTE 205 +#define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206 +#define KVM_CAP_VM_GPA_BITS 207 +#define KVM_CAP_XSAVE2 208 #ifdef KVM_CAP_IRQ_ROUTING @@ -1161,11 +1164,20 @@ struct kvm_irq_routing_hv_sint { __u32 sint; }; +struct kvm_irq_routing_xen_evtchn { + __u32 port; + __u32 vcpu; + __u32 priority; +}; + +#define KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL ((__u32)(-1)) + /* gsi routing entry types */ #define KVM_IRQ_ROUTING_IRQCHIP 1 #define KVM_IRQ_ROUTING_MSI 2 #define KVM_IRQ_ROUTING_S390_ADAPTER 3 #define KVM_IRQ_ROUTING_HV_SINT 4 +#define KVM_IRQ_ROUTING_XEN_EVTCHN 5 struct kvm_irq_routing_entry { __u32 gsi; @@ -1177,6 +1189,7 @@ struct kvm_irq_routing_entry { struct kvm_irq_routing_msi msi; struct kvm_irq_routing_s390_adapter adapter; struct kvm_irq_routing_hv_sint hv_sint; + struct kvm_irq_routing_xen_evtchn xen_evtchn; __u32 pad[8]; } u; }; @@ -1207,6 +1220,7 @@ struct kvm_x86_mce { #define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1) #define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2) #define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3) +#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) struct kvm_xen_hvm_config { __u32 flags; @@ -1609,6 +1623,9 @@ struct kvm_enc_region { #define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3) #define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4) +/* Available with KVM_CAP_XSAVE2 */ +#define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) + struct kvm_s390_pv_sec_parm { __u64 origin; __u64 length; diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 4aedf3ef9b..3765acf9ee 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "qemu/timer.h" #include "user-internals.h" #include "cpu_loop-common.h" #include "signal-common.h" diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c index 38097b02ff..c5d809916f 100644 --- a/linux-user/ppc/cpu_loop.c +++ b/linux-user/ppc/cpu_loop.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "qemu/timer.h" #include "user-internals.h" #include "cpu_loop-common.h" #include "signal-common.h" diff --git a/meson.build b/meson.build index d32f7457e4..bc3d499f56 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('qemu', ['c'], meson_version: '>=0.58.2', +project('qemu', ['c'], meson_version: '>=0.59.3', default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto', 'b_staticpic=false', 'stdsplit=false'], version: files('VERSION')) @@ -44,21 +44,7 @@ config_host_data = configuration_data() genh = [] qapi_trace_events = [] -target_dirs = config_host['TARGET_DIRS'].split() -have_linux_user = false -have_bsd_user = false -have_system = false -foreach target : target_dirs - have_linux_user = have_linux_user or target.endswith('linux-user') - have_bsd_user = have_bsd_user or target.endswith('bsd-user') - have_system = have_system or target.endswith('-softmmu') -endforeach -have_user = have_linux_user or have_bsd_user -have_tools = 'CONFIG_TOOLS' in config_host -have_block = have_system or have_tools - -python = import('python').find_installation() - +bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin'] supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc', 'sparc64'] @@ -72,6 +58,28 @@ endif targetos = host_machine.system() +target_dirs = config_host['TARGET_DIRS'].split() +have_linux_user = false +have_bsd_user = false +have_system = false +foreach target : target_dirs + have_linux_user = have_linux_user or target.endswith('linux-user') + have_bsd_user = have_bsd_user or target.endswith('bsd-user') + have_system = have_system or target.endswith('-softmmu') +endforeach +have_user = have_linux_user or have_bsd_user +have_tools = get_option('tools') \ + .disable_auto_if(not have_system) \ + .allowed() +have_ga = get_option('guest_agent') \ + .disable_auto_if(not have_system and not have_tools) \ + .require(targetos in ['sunos', 'linux', 'windows'], + error_message: 'unsupported OS for QEMU guest agent') \ + .allowed() +have_block = have_system or have_tools + +python = import('python').find_installation() + if cpu not in supported_cpus host_arch = 'unknown' elif cpu == 'x86' @@ -99,7 +107,7 @@ else endif kvm_targets_c = '""' -if not get_option('kvm').disabled() and targetos == 'linux' +if get_option('kvm').allowed() and targetos == 'linux' kvm_targets_c = '"' + '" ,"'.join(kvm_targets) + '"' endif config_host_data.set('CONFIG_KVM_TARGETS', kvm_targets_c) @@ -163,6 +171,16 @@ endif # Compiler flags # ################## +qemu_cflags = config_host['QEMU_CFLAGS'].split() +qemu_cxxflags = config_host['QEMU_CXXFLAGS'].split() +qemu_ldflags = config_host['QEMU_LDFLAGS'].split() + +if get_option('gprof') + qemu_cflags += ['-p'] + qemu_cxxflags += ['-p'] + qemu_ldflags += ['-p'] +endif + # Specify linker-script with add_project_link_arguments so that it is not placed # within a linker --start-group/--end-group pair if get_option('fuzzing') @@ -198,12 +216,9 @@ if get_option('fuzzing') endif endif -add_global_arguments(config_host['QEMU_CFLAGS'].split(), - native: false, language: ['c', 'objc']) -add_global_arguments(config_host['QEMU_CXXFLAGS'].split(), - native: false, language: 'cpp') -add_global_link_arguments(config_host['QEMU_LDFLAGS'].split(), - native: false, language: ['c', 'cpp', 'objc']) +add_global_arguments(qemu_cflags, native: false, language: ['c', 'objc']) +add_global_arguments(qemu_cxxflags, native: false, language: ['cpp']) +add_global_link_arguments(qemu_ldflags, native: false, language: ['c', 'cpp', 'objc']) if targetos == 'linux' add_project_arguments('-isystem', meson.current_source_dir() / 'linux-headers', @@ -269,14 +284,16 @@ if 'syslog' in get_option('trace_backends') and not cc.compiles(''' endif # Miscellaneous Linux-only features -if targetos != 'linux' and get_option('mpath').enabled() - error('Multipath is supported only on Linux') -endif +get_option('mpath') \ + .require(targetos == 'linux', error_message: 'Multipath is supported only on Linux') -if targetos != 'linux' and get_option('multiprocess').enabled() - error('Multiprocess QEMU is supported only on Linux') -endif -multiprocess_allowed = targetos == 'linux' and not get_option('multiprocess').disabled() +multiprocess_allowed = get_option('multiprocess') \ + .require(targetos == 'linux', error_message: 'Multiprocess QEMU is supported only on Linux') \ + .allowed() + +have_tpm = get_option('tpm') \ + .require(targetos != 'windows', error_message: 'TPM emulation only available on POSIX systems') \ + .allowed() # Target-specific libraries and flags libm = cc.find_library('m', required: false) @@ -290,8 +307,12 @@ iokit = [] emulator_link_args = [] nvmm =not_found hvf = not_found +midl = not_found +widl = not_found host_dsosuf = '.so' if targetos == 'windows' + midl = find_program('midl', required: false) + widl = find_program('widl', required: false) socket = cc.find_library('ws2_32') winmm = cc.find_library('winmm') @@ -313,7 +334,7 @@ elif targetos == 'haiku' cc.find_library('network'), cc.find_library('bsd')] elif targetos == 'openbsd' - if not get_option('tcg').disabled() and target_dirs.length() > 0 + if get_option('tcg').allowed() and target_dirs.length() > 0 # Disable OpenBSD W^X if available emulator_link_args = cc.get_supported_link_arguments('-Wl,-z,wxneeded') endif @@ -321,16 +342,16 @@ endif # Target-specific configuration of accelerators accelerators = [] -if not get_option('kvm').disabled() and targetos == 'linux' +if get_option('kvm').allowed() and targetos == 'linux' accelerators += 'CONFIG_KVM' endif -if not get_option('xen').disabled() and 'CONFIG_XEN_BACKEND' in config_host +if get_option('xen').allowed() and 'CONFIG_XEN_BACKEND' in config_host accelerators += 'CONFIG_XEN' - have_xen_pci_passthrough = not get_option('xen_pci_passthrough').disabled() and targetos == 'linux' + have_xen_pci_passthrough = get_option('xen_pci_passthrough').allowed() and targetos == 'linux' else have_xen_pci_passthrough = false endif -if not get_option('whpx').disabled() and targetos == 'windows' +if get_option('whpx').allowed() and targetos == 'windows' if get_option('whpx').enabled() and host_machine.cpu() != 'x86_64' error('WHPX requires 64-bit host') elif cc.has_header('WinHvPlatform.h', required: get_option('whpx')) and \ @@ -338,14 +359,14 @@ if not get_option('whpx').disabled() and targetos == 'windows' accelerators += 'CONFIG_WHPX' endif endif -if not get_option('hvf').disabled() +if get_option('hvf').allowed() hvf = dependency('appleframeworks', modules: 'Hypervisor', required: get_option('hvf')) if hvf.found() accelerators += 'CONFIG_HVF' endif endif -if not get_option('hax').disabled() +if get_option('hax').allowed() if get_option('hax').enabled() or targetos in ['windows', 'darwin', 'netbsd'] accelerators += 'CONFIG_HAX' endif @@ -358,7 +379,7 @@ if targetos == 'netbsd' endif tcg_arch = host_arch -if not get_option('tcg').disabled() +if get_option('tcg').allowed() if host_arch == 'unknown' if get_option('tcg_interpreter') warning('Unsupported CPU @0@, will use TCG with TCI (slow)'.format(cpu)) @@ -472,7 +493,7 @@ libattr_test = ''' libattr = not_found have_old_libattr = false -if not get_option('attr').disabled() +if get_option('attr').allowed() if cc.links(libattr_test) libattr = declare_dependency() else @@ -604,7 +625,9 @@ if not get_option('zstd').auto() or have_block method: 'pkg-config', kwargs: static_kwargs) endif virgl = not_found -if not get_option('virglrenderer').auto() or have_system + +have_vhost_user_gpu = have_tools and targetos == 'linux' and pixman.found() +if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu virgl = dependency('virglrenderer', method: 'pkg-config', required: get_option('virglrenderer'), @@ -628,7 +651,7 @@ endif mpathlibs = [libudev] mpathpersist = not_found mpathpersist_new_api = false -if targetos == 'linux' and have_tools and not get_option('mpath').disabled() +if targetos == 'linux' and have_tools and get_option('mpath').allowed() mpath_test_source_new = ''' #include #include @@ -697,7 +720,7 @@ endif iconv = not_found curses = not_found -if have_system and not get_option('curses').disabled() +if have_system and get_option('curses').allowed() curses_test = ''' #if defined(__APPLE__) || defined(__OpenBSD__) #define _XOPEN_SOURCE_EXTENDED 1 @@ -759,7 +782,7 @@ if have_system and not get_option('curses').disabled() endforeach endif endif - if not get_option('iconv').disabled() + if get_option('iconv').allowed() foreach link_args : [ ['-liconv'], [] ] # Programs will be linked with glib and this will bring in libiconv on FreeBSD. # We need to use libiconv if available because mixing libiconv's headers with @@ -938,7 +961,7 @@ if liblzfse.found() and not cc.links(''' endif oss = not_found -if have_system and not get_option('oss').disabled() +if get_option('oss').allowed() and have_system if not cc.has_header('sys/soundcard.h') # not found elif targetos == 'netbsd' @@ -983,6 +1006,7 @@ if (have_system or have_tools) and (virgl.found() or opengl.found()) gbm = dependency('gbm', method: 'pkg-config', required: false, kwargs: static_kwargs) endif +have_vhost_user_gpu = have_vhost_user_gpu and virgl.found() and gbm.found() gnutls = not_found gnutls_crypto = not_found @@ -1092,7 +1116,7 @@ vnc = not_found png = not_found jpeg = not_found sasl = not_found -if have_system and not get_option('vnc').disabled() +if get_option('vnc').allowed() and have_system vnc = declare_dependency() # dummy dependency png = dependency('libpng', required: get_option('vnc_png'), method: 'pkg-config', kwargs: static_kwargs) @@ -1166,14 +1190,28 @@ if lzo.found() and not cc.links(''' endif endif +numa = not_found +if not get_option('numa').auto() or have_system or have_tools + numa = cc.find_library('numa', has_headers: ['numa.h'], + required: get_option('numa'), + kwargs: static_kwargs) +endif +if numa.found() and not cc.links(''' + #include + int main(void) { return numa_available(); } + ''', dependencies: numa) + numa = not_found + if get_option('numa').enabled() + error('could not link numa') + else + warning('could not link numa, disabling') + endif +endif + rdma = not_found if 'CONFIG_RDMA' in config_host rdma = declare_dependency(link_args: config_host['RDMA_LIBS'].split()) endif -numa = not_found -if 'CONFIG_NUMA' in config_host - numa = declare_dependency(link_args: config_host['NUMA_LIBS'].split()) -endif xen = not_found if 'CONFIG_XEN_BACKEND' in config_host xen = declare_dependency(compile_args: config_host['XEN_CFLAGS'].split(), @@ -1236,7 +1274,7 @@ selinux = dependency('libselinux', malloc = [] if get_option('malloc') == 'system' has_malloc_trim = \ - not get_option('malloc_trim').disabled() and \ + get_option('malloc_trim').allowed() and \ cc.links('''#include int main(void) { malloc_trim(0); return 0; }''') else @@ -1268,19 +1306,13 @@ statx_test = gnu_source_prefix + ''' has_statx = cc.links(statx_test) -have_vhost_user_blk_server = (targetos == 'linux' and - 'CONFIG_VHOST_USER' in config_host) - -if get_option('vhost_user_blk_server').enabled() - if targetos != 'linux' - error('vhost_user_blk_server requires linux') - elif 'CONFIG_VHOST_USER' not in config_host - error('vhost_user_blk_server requires vhost-user support') - endif -elif get_option('vhost_user_blk_server').disabled() or not have_system - have_vhost_user_blk_server = false -endif - +have_vhost_user_blk_server = get_option('vhost_user_blk_server') \ + .require(targetos == 'linux', + error_message: 'vhost_user_blk_server requires linux') \ + .require('CONFIG_VHOST_USER' in config_host, + error_message: 'vhost_user_blk_server requires vhost-user support') \ + .disable_auto_if(not have_system) \ + .allowed() if get_option('fuse').disabled() and get_option('fuse_lseek').enabled() error('Cannot enable fuse-lseek while fuse is disabled') @@ -1291,7 +1323,7 @@ fuse = dependency('fuse3', required: get_option('fuse'), kwargs: static_kwargs) fuse_lseek = not_found -if not get_option('fuse_lseek').disabled() +if get_option('fuse_lseek').allowed() if fuse.version().version_compare('>=3.8') # Dummy dependency fuse_lseek = declare_dependency() @@ -1407,41 +1439,33 @@ endif have_host_block_device = (targetos != 'darwin' or cc.has_header('IOKit/storage/IOMedia.h')) -dbus_display = false -if not get_option('dbus_display').disabled() - # FIXME enable_modules shouldn't be necessary, but: https://github.com/mesonbuild/meson/issues/8333 - dbus_display = gio.version().version_compare('>=2.64') and config_host.has_key('GDBUS_CODEGEN') and enable_modules - if get_option('dbus_display').enabled() and not dbus_display - error('Requirements missing to enable -display dbus (glib>=2.64 && --enable-modules)') - endif -endif +# FIXME enable_modules shouldn't be necessary, but: https://github.com/mesonbuild/meson/issues/8333 +dbus_display = get_option('dbus_display') \ + .require(gio.version().version_compare('>=2.64'), + error_message: '-display dbus requires glib>=2.64') \ + .require(enable_modules, + error_message: '-display dbus requires --enable-modules') \ + .require(config_host.has_key('GDBUS_CODEGEN'), + error_message: '-display dbus requires gdbus-codegen') \ + .allowed() -have_virtfs = (targetos == 'linux' and - have_system and - libattr.found() and - libcap_ng.found()) +have_virtfs = get_option('virtfs') \ + .require(targetos == 'linux', + error_message: 'virtio-9p (virtfs) requires Linux') \ + .require(libattr.found() and libcap_ng.found(), + error_message: 'virtio-9p (virtfs) requires libcap-ng-devel and libattr-devel') \ + .disable_auto_if(not have_tools and not have_system) \ + .allowed() have_virtfs_proxy_helper = have_virtfs and have_tools -if get_option('virtfs').enabled() - if not have_virtfs - if targetos != 'linux' - error('virtio-9p (virtfs) requires Linux') - elif not libcap_ng.found() or not libattr.found() - error('virtio-9p (virtfs) requires libcap-ng-devel and libattr-devel') - elif not have_system - error('virtio-9p (virtfs) needs system emulation support') - endif - endif -elif get_option('virtfs').disabled() - have_virtfs = false -endif - foreach k : get_option('trace_backends') config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true) endforeach config_host_data.set_quoted('CONFIG_TRACE_FILE', get_option('trace_file')) - +if get_option('iasl') != '' + config_host_data.set_quoted('CONFIG_IASL', get_option('iasl')) +endif config_host_data.set_quoted('CONFIG_BINDIR', get_option('prefix') / get_option('bindir')) config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix')) config_host_data.set_quoted('CONFIG_QEMU_CONFDIR', get_option('prefix') / qemu_confdir) @@ -1455,9 +1479,21 @@ config_host_data.set_quoted('CONFIG_QEMU_LOCALSTATEDIR', get_option('prefix') / config_host_data.set_quoted('CONFIG_QEMU_MODDIR', get_option('prefix') / qemu_moddir) config_host_data.set_quoted('CONFIG_SYSCONFDIR', get_option('prefix') / get_option('sysconfdir')) +have_slirp_smbd = get_option('slirp_smbd') \ + .require(targetos != 'windows', error_message: 'Host smbd not supported on this platform.') \ + .allowed() +if have_slirp_smbd + smbd_path = get_option('smbd') + if smbd_path == '' + smbd_path = (targetos == 'solaris' ? '/usr/sfw/sbin/smbd' : '/usr/sbin/smbd') + endif + config_host_data.set_quoted('CONFIG_SMBD_COMMAND', smbd_path) +endif + config_host_data.set('HOST_' + host_arch.to_upper(), 1) config_host_data.set('CONFIG_ATTR', libattr.found()) +config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools')) config_host_data.set('CONFIG_BRLAPI', brlapi.found()) config_host_data.set('CONFIG_COCOA', cocoa.found()) config_host_data.set('CONFIG_FUZZ', get_option('fuzzing')) @@ -1490,11 +1526,14 @@ config_host_data.set('CONFIG_LIBSSH', libssh.found()) config_host_data.set('CONFIG_LINUX_AIO', libaio.found()) config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found()) config_host_data.set('CONFIG_LIBPMEM', libpmem.found()) +config_host_data.set('CONFIG_NUMA', numa.found()) +config_host_data.set('CONFIG_PROFILER', get_option('profiler')) config_host_data.set('CONFIG_RBD', rbd.found()) config_host_data.set('CONFIG_SDL', sdl.found()) config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found()) config_host_data.set('CONFIG_SECCOMP', seccomp.found()) config_host_data.set('CONFIG_SNAPPY', snappy.found()) +config_host_data.set('CONFIG_TPM', have_tpm) config_host_data.set('CONFIG_USB_LIBUSB', libusb.found()) config_host_data.set('CONFIG_VDE', vde.found()) config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server) @@ -1537,6 +1576,19 @@ config_host_data.set_quoted('CONFIG_HOST_DSOSUF', host_dsosuf) config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device) config_host_data.set('HOST_WORDS_BIGENDIAN', host_machine.endian() == 'big') +have_coroutine_pool = get_option('coroutine_pool') +if get_option('debug_stack_usage') and have_coroutine_pool + message('Disabling coroutine pool to measure stack usage') + have_coroutine_pool = false +endif +config_host_data.set10('CONFIG_COROUTINE_POOL', have_coroutine_pool) +config_host_data.set('CONFIG_DEBUG_MUTEX', get_option('debug_mutex')) +config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage')) +config_host_data.set('CONFIG_GPROF', get_option('gprof')) +config_host_data.set('CONFIG_LIVE_BLOCK_MIGRATION', get_option('live_block_migration').allowed()) +config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug')) +config_host_data.set('CONFIG_REPLICATION', get_option('live_block_migration').allowed()) + # 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')) @@ -1714,7 +1766,7 @@ config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + ''' }''')) have_l2tpv3 = false -if not get_option('l2tpv3').disabled() and have_system +if get_option('l2tpv3').allowed() and have_system have_l2tpv3 = cc.has_type('struct mmsghdr', prefix: gnu_source_prefix + ''' #include @@ -1723,7 +1775,7 @@ endif config_host_data.set('CONFIG_L2TPV3', have_l2tpv3) have_netmap = false -if not get_option('netmap').disabled() and have_system +if get_option('netmap').allowed() and have_system have_netmap = cc.compiles(''' #include #include @@ -1780,6 +1832,86 @@ config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + ''' return getauxval(AT_HWCAP) == 0; }''')) +have_cpuid_h = cc.links(''' + #include + int main(void) { + unsigned a, b, c, d; + unsigned max = __get_cpuid_max(0, 0); + + if (max >= 1) { + __cpuid(1, a, b, c, d); + } + + if (max >= 7) { + __cpuid_count(7, 0, a, b, c, d); + } + + return 0; + }''') +config_host_data.set('CONFIG_CPUID_H', have_cpuid_h) + +config_host_data.set('CONFIG_AVX2_OPT', get_option('avx2') \ + .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX2') \ + .require(cc.links(''' + #pragma GCC push_options + #pragma GCC target("avx2") + #include + #include + static int bar(void *a) { + __m256i x = *(__m256i *)a; + return _mm256_testz_si256(x, x); + } + int main(int argc, char *argv[]) { return bar(argv[0]); } + '''), error_message: 'AVX2 not available').allowed()) + +config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \ + .require(have_cpuid_h, error_message: 'cpuid.h not available, cannot enable AVX512F') \ + .require(cc.links(''' + #pragma GCC push_options + #pragma GCC target("avx512f") + #include + #include + static int bar(void *a) { + __m512i x = *(__m512i *)a; + return _mm512_test_epi64_mask(x, x); + } + int main(int argc, char *argv[]) { return bar(argv[0]); } + '''), error_message: 'AVX512F not available').allowed()) + +if get_option('membarrier').disabled() + have_membarrier = false +elif targetos == 'windows' + have_membarrier = true +elif targetos == 'linux' + have_membarrier = cc.compiles(''' + #include + #include + #include + #include + int main(void) { + syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0); + syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0); + exit(0); + }''') +endif +config_host_data.set('CONFIG_MEMBARRIER', get_option('membarrier') \ + .require(have_membarrier, error_message: 'membarrier system call not available') \ + .allowed()) + +have_afalg = get_option('crypto_afalg') \ + .require(cc.compiles(gnu_source_prefix + ''' + #include + #include + #include + #include + int main(void) { + int sock; + sock = socket(AF_ALG, SOCK_SEQPACKET, 0); + return sock; + } + '''), error_message: 'AF_ALG requested but could not be detected').allowed() +config_host_data.set('CONFIG_AF_ALG', have_afalg) + config_host_data.set('CONFIG_AF_VSOCK', cc.compiles(gnu_source_prefix + ''' #include #include @@ -1800,10 +1932,33 @@ config_host_data.set('CONFIG_AF_VSOCK', cc.compiles(gnu_source_prefix + ''' return -1; }''')) +have_vss = false +if targetos == 'windows' and link_language == 'cpp' + have_vss = cxx.compiles(''' + #define __MIDL_user_allocate_free_DEFINED__ + #include + int main(void) { return VSS_CTX_BACKUP; }''') +endif + +have_ntddscsi = false +if targetos == 'windows' + have_ntddscsi = cc.compiles(''' + #include + #include + int main(void) { + #if !defined(IOCTL_SCSI_GET_ADDRESS) + #error Missing required ioctl definitions + #endif + SCSI_ADDRESS addr = { .Lun = 0, .TargetId = 0, .PathId = 0 }; + return addr.Lun; + } +''') +endif +config_host_data.set('HAVE_NTDDSCSI', have_ntddscsi) + ignored = ['CONFIG_QEMU_INTERP_PREFIX', # actually per-target 'HAVE_GDB_BIN'] arrays = ['CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST'] -strings = ['CONFIG_IASL'] foreach k, v: config_host if ignored.contains(k) # do nothing @@ -1812,8 +1967,6 @@ foreach k, v: config_host v = '"' + '", "'.join(v.split()) + '", ' endif config_host_data.set(k, v) - elif strings.contains(k) - config_host_data.set_quoted(k, v) elif k.startswith('CONFIG_') config_host_data.set(k, v == 'y' ? 1 : v) endif @@ -1865,7 +2018,7 @@ endif have_ivshmem = config_host_data.get('CONFIG_EVENTFD') host_kconfig = \ (get_option('fuzzing') ? ['CONFIG_FUZZ=y'] : []) + \ - ('CONFIG_TPM' in config_host ? ['CONFIG_TPM=y'] : []) + \ + (have_tpm ? ['CONFIG_TPM=y'] : []) + \ (spice.found() ? ['CONFIG_SPICE=y'] : []) + \ (have_ivshmem ? ['CONFIG_IVSHMEM=y'] : []) + \ ('CONFIG_OPENGL' in config_host ? ['CONFIG_OPENGL=y'] : []) + \ @@ -2606,7 +2759,9 @@ if have_block 'job.c', 'qemu-io-cmds.c', )) - block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c')) + if config_host_data.get('CONFIG_REPLICATION') + block_ss.add(files('replication.c')) + endif subdir('nbd') subdir('scsi') @@ -3134,11 +3289,7 @@ if 'CONFIG_PLUGIN' in config_host install_headers('include/qemu/qemu-plugin.h') endif -if 'CONFIG_GUEST_AGENT' in config_host - subdir('qga') -elif get_option('guest_agent_msi').enabled() - error('Guest agent MSI requested, but the guest agent is not being built') -endif +subdir('qga') # Don't build qemu-keymap if xkbcommon is not explicitly enabled # when we don't build tools or system @@ -3260,12 +3411,17 @@ summary_info += {'sphinx-build': sphinx_build} if config_host.has_key('HAVE_GDB_BIN') summary_info += {'gdb': config_host['HAVE_GDB_BIN']} endif +if get_option('iasl') != '' + summary_info += {'iasl': get_option('iasl')} +else + summary_info += {'iasl': false} +endif summary_info += {'genisoimage': config_host['GENISOIMAGE']} -if targetos == 'windows' and config_host.has_key('CONFIG_GUEST_AGENT') +if targetos == 'windows' and have_ga summary_info += {'wixl': wixl} endif -if slirp_opt != 'disabled' and 'CONFIG_SLIRP_SMBD' in config_host - summary_info += {'smbd': config_host['CONFIG_SMBD_COMMAND']} +if slirp_opt != 'disabled' and have_system + summary_info += {'smbd': have_slirp_smbd ? smbd_path : false} endif summary(summary_info, bool_yn: true, section: 'Host binaries') @@ -3289,7 +3445,7 @@ if 'simple' in get_option('trace_backends') summary_info += {'Trace output file': get_option('trace_file') + '-'} endif summary_info += {'D-Bus display': dbus_display} -summary_info += {'QOM debugging': config_host.has_key('CONFIG_QOM_CAST_DEBUG')} +summary_info += {'QOM debugging': get_option('qom_cast_debug')} summary_info += {'vhost-kernel support': config_host.has_key('CONFIG_VHOST_KERNEL')} summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} summary_info += {'vhost-crypto support': config_host.has_key('CONFIG_VHOST_CRYPTO')} @@ -3299,7 +3455,7 @@ summary_info += {'vhost-user support': config_host.has_key('CONFIG_VHOST_USER')} summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server} summary_info += {'vhost-user-fs support': config_host.has_key('CONFIG_VHOST_USER_FS')} summary_info += {'vhost-vdpa support': config_host.has_key('CONFIG_VHOST_VDPA')} -summary_info += {'build guest agent': config_host.has_key('CONFIG_GUEST_AGENT')} +summary_info += {'build guest agent': have_ga} summary(summary_info, bool_yn: true, section: 'Configurable features') # Compilation information @@ -3316,11 +3472,6 @@ endif if targetos == 'darwin' summary_info += {'Objective-C compiler': ' '.join(meson.get_compiler('objc').cmd_array())} endif -if targetos == 'windows' - if 'WIN_SDK' in config_host - summary_info += {'Windows SDK': config_host['WIN_SDK']} - endif -endif summary_info += {'CFLAGS': ' '.join(get_option('c_args') + ['-O' + get_option('optimization')] + (get_option('debug') ? ['-g'] : []))} @@ -3335,18 +3486,18 @@ if link_args.length() > 0 endif summary_info += {'QEMU_CFLAGS': config_host['QEMU_CFLAGS']} summary_info += {'QEMU_LDFLAGS': config_host['QEMU_LDFLAGS']} -summary_info += {'profiler': config_host.has_key('CONFIG_PROFILER')} +summary_info += {'profiler': get_option('profiler')} summary_info += {'link-time optimization (LTO)': get_option('b_lto')} summary_info += {'PIE': get_option('b_pie')} summary_info += {'static build': config_host.has_key('CONFIG_STATIC')} summary_info += {'malloc trim support': has_malloc_trim} -summary_info += {'membarrier': config_host.has_key('CONFIG_MEMBARRIER')} -summary_info += {'debug stack usage': config_host.has_key('CONFIG_DEBUG_STACK_USAGE')} -summary_info += {'mutex debugging': config_host.has_key('CONFIG_DEBUG_MUTEX')} +summary_info += {'membarrier': have_membarrier} +summary_info += {'debug stack usage': get_option('debug_stack_usage')} +summary_info += {'mutex debugging': get_option('debug_mutex')} summary_info += {'memory allocator': get_option('malloc')} -summary_info += {'avx2 optimization': config_host.has_key('CONFIG_AVX2_OPT')} -summary_info += {'avx512f optimization': config_host.has_key('CONFIG_AVX512F_OPT')} -summary_info += {'gprof enabled': config_host.has_key('CONFIG_GPROF')} +summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')} +summary_info += {'avx512f optimization': config_host_data.get('CONFIG_AVX512F_OPT')} +summary_info += {'gprof enabled': get_option('gprof')} summary_info += {'gcov': get_option('b_coverage')} summary_info += {'thread sanitizer': config_host.has_key('CONFIG_TSAN')} summary_info += {'CFI support': get_option('cfi')} @@ -3409,23 +3560,23 @@ summary(summary_info, bool_yn: true, section: 'Targets and accelerators') # Block layer summary_info = {} summary_info += {'coroutine backend': config_host['CONFIG_COROUTINE_BACKEND']} -summary_info += {'coroutine pool': config_host['CONFIG_COROUTINE_POOL'] == '1'} +summary_info += {'coroutine pool': have_coroutine_pool} if have_block summary_info += {'Block whitelist (rw)': config_host['CONFIG_BDRV_RW_WHITELIST']} summary_info += {'Block whitelist (ro)': config_host['CONFIG_BDRV_RO_WHITELIST']} - summary_info += {'Use block whitelist in tools': config_host.has_key('CONFIG_BDRV_WHITELIST_TOOLS')} + summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')} summary_info += {'VirtFS support': have_virtfs} summary_info += {'build virtiofs daemon': have_virtiofsd} - summary_info += {'Live block migration': config_host.has_key('CONFIG_LIVE_BLOCK_MIGRATION')} - summary_info += {'replication support': config_host.has_key('CONFIG_REPLICATION')} - summary_info += {'bochs support': config_host.has_key('CONFIG_BOCHS')} - summary_info += {'cloop support': config_host.has_key('CONFIG_CLOOP')} - summary_info += {'dmg support': config_host.has_key('CONFIG_DMG')} - summary_info += {'qcow v1 support': config_host.has_key('CONFIG_QCOW1')} - summary_info += {'vdi support': config_host.has_key('CONFIG_VDI')} - summary_info += {'vvfat support': config_host.has_key('CONFIG_VVFAT')} - summary_info += {'qed support': config_host.has_key('CONFIG_QED')} - summary_info += {'parallels support': config_host.has_key('CONFIG_PARALLELS')} + summary_info += {'Live block migration': config_host_data.get('CONFIG_LIVE_BLOCK_MIGRATION')} + summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')} + summary_info += {'bochs support': get_option('bochs').allowed()} + summary_info += {'cloop support': get_option('cloop').allowed()} + summary_info += {'dmg support': get_option('dmg').allowed()} + summary_info += {'qcow v1 support': get_option('qcow1').allowed()} + summary_info += {'vdi support': get_option('vdi').allowed()} + summary_info += {'vvfat support': get_option('vvfat').allowed()} + summary_info += {'qed support': get_option('qed').allowed()} + summary_info += {'parallels support': get_option('parallels').allowed()} summary_info += {'FUSE exports': fuse} endif summary(summary_info, bool_yn: true, section: 'Block layer support') @@ -3442,8 +3593,8 @@ summary_info += {'nettle': nettle} if nettle.found() summary_info += {' XTS': xts != 'private'} endif -summary_info += {'crypto afalg': config_host.has_key('CONFIG_AF_ALG')} -summary_info += {'rng-none': config_host.has_key('CONFIG_RNG_NONE')} +summary_info += {'AF_ALG support': have_afalg} +summary_info += {'rng-none': get_option('rng_none')} summary_info += {'Linux keyring': config_host.has_key('CONFIG_SECRET_KEYRING')} summary(summary_info, bool_yn: true, section: 'Crypto') @@ -3509,21 +3660,21 @@ summary_info += {'GBM': gbm} summary_info += {'libiscsi support': libiscsi} summary_info += {'libnfs support': libnfs} if targetos == 'windows' - if config_host.has_key('CONFIG_GUEST_AGENT') - summary_info += {'QGA VSS support': config_host.has_key('CONFIG_QGA_VSS')} - summary_info += {'QGA w32 disk info': config_host.has_key('CONFIG_QGA_NTDDSCSI')} + if have_ga + summary_info += {'QGA VSS support': have_qga_vss} + summary_info += {'QGA w32 disk info': have_ntddscsi} endif endif summary_info += {'seccomp support': seccomp} summary_info += {'GlusterFS support': glusterfs} -summary_info += {'TPM support': config_host.has_key('CONFIG_TPM')} +summary_info += {'TPM support': have_tpm} summary_info += {'libssh support': libssh} summary_info += {'lzo support': lzo} summary_info += {'snappy support': snappy} summary_info += {'bzip2 support': libbzip2} summary_info += {'lzfse support': liblzfse} summary_info += {'zstd support': zstd} -summary_info += {'NUMA host support': config_host.has_key('CONFIG_NUMA')} +summary_info += {'NUMA host support': numa} summary_info += {'capstone': capstone_opt == 'internal' ? capstone_opt : capstone} summary_info += {'libpmem support': libpmem} summary_info += {'libdaxctl support': libdaxctl} diff --git a/meson_options.txt b/meson_options.txt index 95d527f773..52b11cead4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,8 +8,12 @@ option('docdir', type : 'string', value : 'doc', description: 'Base directory for documentation installation (can be empty)') option('qemu_firmwarepath', type : 'string', value : '', description: 'search PATH for firmware files') +option('smbd', type : 'string', value : '', + description: 'Path to smbd for slirp networking') option('sphinx_build', type : 'string', value : '', description: 'Use specified sphinx-build [$sphinx_build] for building document (default to be empty)') +option('iasl', type : 'string', value : '', + description: 'Path to ACPI disassembler') option('default_devices', type : 'boolean', value : true, description: 'Include a default selection of devices in emulators') option('audio_drv_list', type: 'array', value: ['default'], @@ -34,8 +38,14 @@ option('install_blobs', type : 'boolean', value : true, description: 'install provided firmware blobs') option('sparse', type : 'feature', value : 'auto', description: 'sparse checker') +option('guest_agent', type : 'feature', value : 'auto', + description: 'Build QEMU Guest Agent') option('guest_agent_msi', type : 'feature', value : 'auto', description: 'Build MSI package for the QEMU Guest Agent') +option('tools', type : 'feature', value : 'auto', + description: 'build support utilities that come with QEMU') +option('qga_vss', type : 'feature', value: 'auto', + description: 'build QGA VSS support (broken with MinGW)') option('malloc_trim', type : 'feature', value : 'auto', description: 'enable libc malloc_trim() for memory optimization') @@ -68,6 +78,18 @@ option('multiprocess', type: 'feature', value: 'auto', description: 'Out of process device emulation support') option('dbus_display', type: 'feature', value: 'auto', description: '-display dbus support') +option('tpm', type : 'feature', value : 'auto', + description: 'TPM support') + +# Do not enable it by default even for Mingw32, because it doesn't +# work on Wine. +option('membarrier', type: 'feature', value: 'disabled', + description: 'membarrier system call (for Linux 4.14+ or Windows') + +option('avx2', type: 'feature', value: 'auto', + description: 'AVX2 optimizations') +option('avx512f', type: 'feature', value: 'disabled', + description: 'AVX512F optimizations') option('attr', type : 'feature', value : 'auto', description: 'attr/xattr support') @@ -93,6 +115,8 @@ option('libnfs', type : 'feature', value : 'auto', description: 'libnfs block device driver') option('mpath', type : 'feature', value : 'auto', description: 'Multipath persistent reservation passthrough') +option('numa', type : 'feature', value : 'auto', + description: 'libnuma support') option('iconv', type : 'feature', value : 'auto', description: 'Font glyph conversion support') option('curses', type : 'feature', value : 'auto', @@ -103,6 +127,8 @@ option('nettle', type : 'feature', value : 'auto', description: 'nettle cryptography support') option('gcrypt', type : 'feature', value : 'auto', description: 'libgcrypt cryptography support') +option('crypto_afalg', type : 'feature', value : 'disabled', + description: 'Linux AF_ALG crypto backend driver') option('libdaxctl', type : 'feature', value : 'auto', description: 'libdaxctl support') option('libpmem', type : 'feature', value : 'auto', @@ -206,3 +232,41 @@ option('fdt', type: 'combo', value: 'auto', option('selinux', type: 'feature', value: 'auto', description: 'SELinux support in qemu-nbd') +option('live_block_migration', type: 'feature', value: 'auto', + description: 'block migration in the main migration stream') +option('replication', type: 'feature', value: 'auto', + description: 'replication support') +option('bochs', type: 'feature', value: 'auto', + description: 'bochs image format support') +option('cloop', type: 'feature', value: 'auto', + description: 'cloop image format support') +option('dmg', type: 'feature', value: 'auto', + description: 'dmg image format support') +option('qcow1', type: 'feature', value: 'auto', + description: 'qcow1 image format support') +option('vdi', type: 'feature', value: 'auto', + description: 'vdi image format support') +option('vvfat', type: 'feature', value: 'auto', + description: 'vvfat image format support') +option('qed', type: 'feature', value: 'auto', + description: 'qed image format support') +option('parallels', type: 'feature', value: 'auto', + description: 'parallels image format support') +option('block_drv_whitelist_in_tools', type: 'boolean', value: false, + description: 'use block whitelist also in tools instead of only QEMU') +option('rng_none', type: 'boolean', value: false, + description: 'dummy RNG, avoid using /dev/(u)random and getrandom()') +option('coroutine_pool', type: 'boolean', value: true, + description: 'coroutine freelist (better performance)') +option('debug_mutex', type: 'boolean', value: false, + description: 'mutex debugging support') +option('debug_stack_usage', type: 'boolean', value: false, + description: 'measure coroutine stack usage') +option('qom_cast_debug', type: 'boolean', value: false, + description: 'cast debugging support') +option('gprof', type: 'boolean', value: false, + description: 'QEMU profiling with gprof') +option('profiler', type: 'boolean', value: false, + description: 'profiler support') +option('slirp_smbd', type : 'feature', value : 'auto', + description: 'use smbd (at path --smbd=*) in slirp networking') diff --git a/migration/meson.build b/migration/meson.build index f8714dcb15..8b5ca5c047 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -28,7 +28,9 @@ softmmu_ss.add(files( ), gnutls) softmmu_ss.add(when: ['CONFIG_RDMA', rdma], if_true: files('rdma.c')) -softmmu_ss.add(when: 'CONFIG_LIVE_BLOCK_MIGRATION', if_true: files('block.c')) +if get_option('live_block_migration').allowed() + softmmu_ss.add(files('block.c')) +endif softmmu_ss.add(when: zstd, if_true: files('multifd-zstd.c')) specific_ss.add(when: 'CONFIG_SOFTMMU', diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index e662dd05cc..2a2cc5faf8 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" #include "qemu/rcu.h" +#include "qemu/madvise.h" #include "exec/target_page.h" #include "migration.h" #include "qemu-file.h" diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 6338d8e2ff..1479cddad9 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" #include +#include "qemu/madvise.h" #include "qemu/error-report.h" #include "qemu/iov.h" #include "migration.h" diff --git a/migration/ram.c b/migration/ram.c index 91ca743ac8..781f0745dc 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -30,6 +30,7 @@ #include "qemu/cutils.h" #include "qemu/bitops.h" #include "qemu/bitmap.h" +#include "qemu/madvise.h" #include "qemu/main-loop.h" #include "xbzrle.h" #include "ram.h" diff --git a/monitor/misc.c b/monitor/misc.c index a3a6e47844..b1839cb8ee 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -41,6 +41,7 @@ #include "disas/disas.h" #include "sysemu/balloon.h" #include "qemu/timer.h" +#include "qemu/log.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" #include "authz/list.h" diff --git a/net/slirp.c b/net/slirp.c index ad3a838e0b..bc5e9e4f77 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -27,7 +27,7 @@ #include "net/slirp.h" -#if defined(CONFIG_SLIRP_SMBD) +#if defined(CONFIG_SMBD_COMMAND) #include #include #endif @@ -91,7 +91,7 @@ typedef struct SlirpState { Slirp *slirp; Notifier poll_notifier; Notifier exit_notifier; -#if defined(CONFIG_SLIRP_SMBD) +#if defined(CONFIG_SMBD_COMMAND) gchar *smb_dir; #endif GSList *fwd; @@ -104,7 +104,7 @@ static QTAILQ_HEAD(, SlirpState) slirp_stacks = static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp); static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp); -#if defined(CONFIG_SLIRP_SMBD) +#if defined(CONFIG_SMBD_COMMAND) static int slirp_smb(SlirpState *s, const char *exported_dir, struct in_addr vserver_addr, Error **errp); static void slirp_smb_cleanup(SlirpState *s); @@ -377,7 +377,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, struct in6_addr ip6_prefix; struct in6_addr ip6_host; struct in6_addr ip6_dns; -#if defined(CONFIG_SLIRP_SMBD) +#if defined(CONFIG_SMBD_COMMAND) struct in_addr smbsrv = { .s_addr = 0 }; #endif NetClientState *nc; @@ -487,7 +487,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, return -1; } -#if defined(CONFIG_SLIRP_SMBD) +#if defined(CONFIG_SMBD_COMMAND) if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) { error_setg(errp, "Failed to parse SMB address"); return -1; @@ -602,7 +602,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, } } } -#if defined(CONFIG_SLIRP_SMBD) +#if defined(CONFIG_SMBD_COMMAND) if (smb_export) { if (slirp_smb(s, smb_export, smbsrv, errp) < 0) { goto error; @@ -794,7 +794,7 @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict) } -#if defined(CONFIG_SLIRP_SMBD) +#if defined(CONFIG_SMBD_COMMAND) /* automatic user mode samba server configuration */ static void slirp_smb_cleanup(SlirpState *s) @@ -909,7 +909,7 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, return 0; } -#endif /* defined(CONFIG_SLIRP_SMBD) */ +#endif /* defined(CONFIG_SMBD_COMMAND) */ static int guestfwd_can_read(void *opaque) { diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 25dd6dd975..1e9fe47c03 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -263,7 +263,8 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, { const NetdevVhostVDPAOptions *opts; int vdpa_device_fd; - NetClientState **ncs, *nc; + g_autofree NetClientState **ncs = NULL; + NetClientState *nc; int queue_pairs, i, has_cvq = 0; assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); @@ -301,7 +302,6 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, goto err; } - g_free(ncs); return 0; err: @@ -309,7 +309,6 @@ err: qemu_del_net_client(ncs[0]); } qemu_close(vdpa_device_fd); - g_free(ncs); return -1; } diff --git a/plugins/api.c b/plugins/api.c index 91e0c7074c..7bf71b189d 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -36,6 +36,7 @@ #include "qemu/osdep.h" #include "qemu/plugin.h" +#include "qemu/log.h" #include "tcg/tcg.h" #include "exec/exec-all.h" #include "exec/ram_addr.h" diff --git a/plugins/loader.c b/plugins/loader.c index a4ec281692..4883b0a1cb 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -24,6 +24,7 @@ #include "qemu/rcu_queue.h" #include "qemu/qht.h" #include "qemu/bitmap.h" +#include "qemu/cacheinfo.h" #include "qemu/xxhash.h" #include "qemu/plugin.h" #include "hw/core/cpu.h" diff --git a/qemu-options.hx b/qemu-options.hx index ba3ae6a42a..094a6c1d7c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1377,7 +1377,7 @@ SRST the bus number and the unit id. ``index=index`` - This option defines where is connected the drive by using an + This option defines where the drive is connected by using an index in the list of available connectors of a given interface type. diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 484cb1c6bd..4fbbad793f 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -18,7 +18,7 @@ #include #include #include -#ifdef CONFIG_QGA_NTDDSCSI +#ifdef HAVE_NTDDSCSI #include #include #endif @@ -474,7 +474,7 @@ void qmp_guest_file_flush(int64_t handle, Error **errp) } } -#ifdef CONFIG_QGA_NTDDSCSI +#ifdef HAVE_NTDDSCSI static GuestDiskBusType win2qemu[] = { [BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN, @@ -1111,7 +1111,7 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp) return NULL; } -#endif /* CONFIG_QGA_NTDDSCSI */ +#endif /* HAVE_NTDDSCSI */ static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp) { diff --git a/qga/meson.build b/qga/meson.build index 1ee9dca60b..54f2da5b07 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -1,3 +1,33 @@ +if not have_ga + if get_option('guest_agent_msi').enabled() + error('Guest agent MSI requested, but the guest agent is not being built') + endif + have_qga_vss = false + subdir_done() +endif + +have_qga_vss = get_option('qga_vss') \ + .require(targetos == 'windows', + error_message: 'VSS support requires Windows') \ + .require(link_language == 'cpp', + error_message: 'VSS support requires a C++ compiler') \ + .require(have_vss, error_message: '''VSS support requires VSS headers. + If your Visual Studio installation doesn't have the VSS headers, + Please download and install Microsoft VSS SDK: + http://www.microsoft.com/en-us/download/details.aspx?id=23490 + On POSIX-systems, MinGW doesn't yet provide working headers. + you can extract the SDK headers by: + $ scripts/extract-vsssdk-headers setup.exe + The headers are extracted in the directory 'inc/win2003'. + Then run configure with: --extra-cxxflags="-isystem /path/to/vss/inc/win2003"''') \ + .require(midl.found() or widl.found(), + error_message: 'VSS support requires midl or widl') \ + .require(not enable_static, + error_message: 'VSS support requires dynamic linking with GLib') \ + .allowed() + +all_qga = [] + qga_qapi_outputs = [ 'qga-qapi-commands.c', 'qga-qapi-commands.h', @@ -50,19 +80,26 @@ qga_ss.add(when: 'CONFIG_WIN32', if_true: files( qga_ss = qga_ss.apply(config_host, strict: false) +gen_tlb = [] +qga_libs = [] +if targetos == 'windows' + qga_libs += ['-lws2_32', '-lwinmm', '-lpowrprof', '-lwtsapi32', '-lwininet', '-liphlpapi', '-lnetapi32'] + if have_qga_vss + qga_libs += ['-lole32', '-loleaut32', '-lshlwapi', '-lstdc++', '-Wl,--enable-stdcall-fixup'] + subdir('vss-win32') + endif + if have_ntddscsi + qga_libs += ['-lsetupapi', '-lcfgmgr32'] + endif +endif + qga = executable('qemu-ga', qga_ss.sources(), - link_args: config_host['LIBS_QGA'].split(), + link_args: qga_libs, dependencies: [qemuutil, libudev], install: true) -all_qga = [qga] +all_qga += qga if targetos == 'windows' - if 'CONFIG_QGA_VSS' in config_host - subdir('vss-win32') - else - gen_tlb = [] - endif - qemu_ga_msi_arch = { 'x86': ['-D', 'Arch=32'], 'x86_64': ['-a', 'x64', '-D', 'Arch=64'] @@ -77,7 +114,7 @@ if targetos == 'windows' if wixl.found() deps = [gen_tlb, qga] qemu_ga_msi_vss = [] - if 'CONFIG_QGA_VSS' in config_host + if have_qga_vss qemu_ga_msi_vss = ['-D', 'InstallVss'] deps += qga_vss endif diff --git a/qga/vss-win32/install.cpp b/qga/vss-win32/install.cpp index 40de133774..efc5bb9909 100644 --- a/qga/vss-win32/install.cpp +++ b/qga/vss-win32/install.cpp @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "vss-common.h" -#include +#include #include "install.h" #include #include diff --git a/qga/vss-win32/meson.build b/qga/vss-win32/meson.build index 90825edef3..71c50d0866 100644 --- a/qga/vss-win32/meson.build +++ b/qga/vss-win32/meson.build @@ -1,36 +1,38 @@ -if add_languages('cpp', required: false) - glib_dynamic = dependency('glib-2.0', static: false) - link_args = cc.get_supported_link_arguments(['-fstack-protector-all', '-fstack-protector-strong', - '-Wl,--add-stdcall-alias', '-Wl,--enable-stdcall-fixup']) +link_args = cc.get_supported_link_arguments([ + '-fstack-protector-all', + '-fstack-protector-strong', + '-Wl,--add-stdcall-alias', + '-Wl,--enable-stdcall-fixup' +]) - qga_vss = shared_module('qga-vss', ['requester.cpp', 'provider.cpp', 'install.cpp'], - name_prefix: '', - cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'], - link_args: link_args, - vs_module_defs: 'qga-vss.def', - dependencies: [glib_dynamic, socket, - cc.find_library('ole32'), - cc.find_library('oleaut32'), - cc.find_library('shlwapi'), - cc.find_library('uuid'), - cc.find_library('intl')]) +qga_vss = shared_module( + 'qga-vss', + ['requester.cpp', 'provider.cpp', 'install.cpp'], + name_prefix: '', + cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'], + link_args: link_args, + vs_module_defs: 'qga-vss.def', + dependencies: [ + glib, + socket, + cc.find_library('ole32'), + cc.find_library('oleaut32'), + cc.find_library('shlwapi'), + cc.find_library('uuid'), + cc.find_library('intl') + ] +) - all_qga += qga_vss -endif +all_qga += qga_vss -# rules to build qga-vss.tlb -# Currently, only native build is supported because building .tlb -# (TypeLibrary) from .idl requires WindowsSDK and MIDL (and cl.exe in VC++). -midl = find_program('midl', required: false) if midl.found() gen_tlb = custom_target('gen-tlb', input: 'qga-vss.idl', output: 'qga-vss.tlb', - command: [midl, '-tlb', '-I' + config_host['WIN_SDK'], - '@INPUT@', '@OUTPUT@']) + command: [midl, '@INPUT@', '/tlb', '@OUTPUT@']) else gen_tlb = custom_target('gen-tlb', - input: 'qga-vss.tlb', + input: 'qga-vss.idl', output: 'qga-vss.tlb', - command: ['cp', '@INPUT@', '@OUTPUT@']) + command: [widl, '-t', '@INPUT@', '-o', '@OUTPUT@']) endif diff --git a/qga/vss-win32/provider.cpp b/qga/vss-win32/provider.cpp index 72d8b0e19d..fd187fb66f 100644 --- a/qga/vss-win32/provider.cpp +++ b/qga/vss-win32/provider.cpp @@ -12,8 +12,8 @@ #include "qemu/osdep.h" #include "vss-common.h" -#include -#include +#include +#include #define VSS_TIMEOUT_MSEC (60*1000) diff --git a/qga/vss-win32/qga-vss.tlb b/qga/vss-win32/qga-vss.tlb deleted file mode 100644 index 226452a186..0000000000 Binary files a/qga/vss-win32/qga-vss.tlb and /dev/null differ diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index 940a2c8f55..4513324dd2 100644 --- a/qga/vss-win32/requester.cpp +++ b/qga/vss-win32/requester.cpp @@ -14,8 +14,8 @@ #include "vss-common.h" #include "requester.h" #include "install.h" -#include -#include +#include +#include /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */ #define VSS_TIMEOUT_FREEZE_MSEC 60000 diff --git a/qga/vss-win32/vss-common.h b/qga/vss-win32/vss-common.h index 61c170b52e..54f8de8c88 100644 --- a/qga/vss-win32/vss-common.h +++ b/qga/vss-win32/vss-common.h @@ -46,11 +46,7 @@ #undef VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED #undef VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED -/* - * VSS headers must be installed from Microsoft VSS SDK 7.2 available at: - * http://www.microsoft.com/en-us/download/details.aspx?id=23490 - */ -#include +#include #include "vss-handles.h" /* Macros to convert char definitions to wchar */ diff --git a/qom/object.c b/qom/object.c index 4f0677cca9..9f7a33139d 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2793,13 +2793,13 @@ static void object_class_init(ObjectClass *klass, void *data) static void register_types(void) { - static TypeInfo interface_info = { + static const TypeInfo interface_info = { .name = TYPE_INTERFACE, .class_size = sizeof(InterfaceClass), .abstract = true, }; - static TypeInfo object_info = { + static const TypeInfo object_info = { .name = TYPE_OBJECT, .instance_size = sizeof(Object), .class_init = object_class_init, diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 5e50111060..ddd8148d87 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2882,6 +2882,7 @@ sub process { SCSIBusInfo| SCSIReqOps| Spice[A-Z][a-zA-Z0-9]*Interface| + TypeInfo| USBDesc[A-Z][a-zA-Z0-9]*| VhostOps| VMStateDescription| diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py index 98ae944148..693be7b966 100755 --- a/scripts/meson-buildoptions.py +++ b/scripts/meson-buildoptions.py @@ -30,8 +30,10 @@ SKIP_OPTIONS = { "default_devices", "docdir", "fuzzing_engine", + "iasl", "qemu_firmwarepath", "qemu_suffix", + "smbd", "sphinx_build", "trace_file", } diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 48a454cece..9ee684ef03 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -1,16 +1,29 @@ # This file is generated by meson-buildoptions.py, do not edit! meson_options_help() { + printf "%s\n" ' --enable-block-drv-whitelist-in-tools' + printf "%s\n" ' use block whitelist also in tools instead of only' + printf "%s\n" ' QEMU' printf "%s\n" ' --enable-capstone[=CHOICE]' printf "%s\n" ' Whether and how to find the capstone library' printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-cfi Control-Flow Integrity (CFI)' printf "%s\n" ' --enable-cfi-debug Verbose errors in case of CFI violation' + printf "%s\n" ' --disable-coroutine-pool coroutine freelist (better performance)' + printf "%s\n" ' --enable-debug-mutex mutex debugging support' + printf "%s\n" ' --enable-debug-stack-usage' + printf "%s\n" ' measure coroutine stack usage' printf "%s\n" ' --enable-fdt[=CHOICE] Whether and how to find the libfdt library' printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-fuzzing build fuzzing targets' + printf "%s\n" ' --enable-gprof QEMU profiling with gprof' printf "%s\n" ' --disable-install-blobs install provided firmware blobs' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' + printf "%s\n" ' --enable-profiler profiler support' + printf "%s\n" ' --enable-qga-vss build QGA VSS support' + printf "%s\n" ' --enable-qom-cast-debug cast debugging support' + printf "%s\n" ' --enable-rng-none dummy RNG, avoid using /dev/(u)random and' + printf "%s\n" ' getrandom()' printf "%s\n" ' --enable-slirp[=CHOICE] Whether and how to find the slirp library' printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-strip Strip targets on install' @@ -26,15 +39,21 @@ meson_options_help() { printf "%s\n" ' alsa ALSA sound support' printf "%s\n" ' attr attr/xattr support' printf "%s\n" ' auth-pam PAM access control' + printf "%s\n" ' avx2 AVX2 optimizations' + printf "%s\n" ' avx512f AVX512F optimizations' + printf "%s\n" ' bochs bochs image format support' printf "%s\n" ' bpf eBPF support' printf "%s\n" ' brlapi brlapi character device driver' printf "%s\n" ' bzip2 bzip2 support for DMG images' printf "%s\n" ' cap-ng cap_ng support' + printf "%s\n" ' cloop cloop image format support' printf "%s\n" ' cocoa Cocoa user interface (macOS only)' printf "%s\n" ' coreaudio CoreAudio sound support' + printf "%s\n" ' crypto-afalg Linux AF_ALG crypto backend driver' printf "%s\n" ' curl CURL block device driver' printf "%s\n" ' curses curses UI' printf "%s\n" ' dbus-display -display dbus support' + printf "%s\n" ' dmg dmg image format support' printf "%s\n" ' docs Documentations build support' printf "%s\n" ' dsound DirectSound sound support' printf "%s\n" ' fuse FUSE block device export' @@ -44,6 +63,7 @@ meson_options_help() { printf "%s\n" ' glusterfs Glusterfs block device driver' printf "%s\n" ' gnutls GNUTLS cryptography support' printf "%s\n" ' gtk GTK+ user interface' + printf "%s\n" ' guest-agent Build QEMU Guest Agent' printf "%s\n" ' guest-agent-msi Build MSI package for the QEMU Guest Agent' printf "%s\n" ' hax HAX acceleration support' printf "%s\n" ' hvf HVF acceleration support' @@ -60,30 +80,42 @@ meson_options_help() { printf "%s\n" ' libusb libusb support for USB passthrough' printf "%s\n" ' linux-aio Linux AIO support' printf "%s\n" ' linux-io-uring Linux io_uring support' + printf "%s\n" ' live-block-migration' + printf "%s\n" ' block migration in the main migration stream' printf "%s\n" ' lzfse lzfse support for DMG images' printf "%s\n" ' lzo lzo compression support' printf "%s\n" ' malloc-trim enable libc malloc_trim() for memory optimization' + printf "%s\n" ' membarrier membarrier system call (for Linux 4.14+ or Windows' printf "%s\n" ' mpath Multipath persistent reservation passthrough' printf "%s\n" ' multiprocess Out of process device emulation support' printf "%s\n" ' netmap netmap network backend support' printf "%s\n" ' nettle nettle cryptography support' + printf "%s\n" ' numa libnuma support' printf "%s\n" ' nvmm NVMM acceleration support' printf "%s\n" ' oss OSS sound support' printf "%s\n" ' pa PulseAudio sound support' + printf "%s\n" ' parallels parallels image format support' + printf "%s\n" ' qcow1 qcow1 image format support' + printf "%s\n" ' qed qed image format support' printf "%s\n" ' rbd Ceph block device driver' + printf "%s\n" ' replication replication support' printf "%s\n" ' sdl SDL user interface' printf "%s\n" ' sdl-image SDL Image support for icons' printf "%s\n" ' seccomp seccomp support' printf "%s\n" ' selinux SELinux support in qemu-nbd' + printf "%s\n" ' slirp-smbd use smbd (at path --smbd=*) in slirp networking' printf "%s\n" ' smartcard CA smartcard emulation support' printf "%s\n" ' snappy snappy compression support' printf "%s\n" ' sparse sparse checker' printf "%s\n" ' spice Spice server support' printf "%s\n" ' spice-protocol Spice protocol support' printf "%s\n" ' tcg TCG support' + printf "%s\n" ' tools build support utilities that come with QEMU' + printf "%s\n" ' tpm TPM support' printf "%s\n" ' u2f U2F emulation support' printf "%s\n" ' usb-redir libusbredir support' printf "%s\n" ' vde vde network backend support' + printf "%s\n" ' vdi vdi image format support' printf "%s\n" ' vhost-user-blk-server' printf "%s\n" ' build vhost-user-blk server' printf "%s\n" ' virglrenderer virgl rendering support' @@ -94,6 +126,7 @@ meson_options_help() { printf "%s\n" ' vnc-png PNG compression for VNC server' printf "%s\n" ' vnc-sasl SASL authentication for VNC server' printf "%s\n" ' vte vte support for the gtk UI' + printf "%s\n" ' vvfat vvfat image format support' printf "%s\n" ' whpx WHPX acceleration support' printf "%s\n" ' xen Xen backend support' printf "%s\n" ' xen-pci-passthrough' @@ -109,6 +142,14 @@ _meson_option_parse() { --disable-attr) printf "%s" -Dattr=disabled ;; --enable-auth-pam) printf "%s" -Dauth_pam=enabled ;; --disable-auth-pam) printf "%s" -Dauth_pam=disabled ;; + --enable-avx2) printf "%s" -Davx2=enabled ;; + --disable-avx2) printf "%s" -Davx2=disabled ;; + --enable-avx512f) printf "%s" -Davx512f=enabled ;; + --disable-avx512f) printf "%s" -Davx512f=disabled ;; + --enable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=true ;; + --disable-block-drv-whitelist-in-tools) printf "%s" -Dblock_drv_whitelist_in_tools=false ;; + --enable-bochs) printf "%s" -Dbochs=enabled ;; + --disable-bochs) printf "%s" -Dbochs=disabled ;; --enable-bpf) printf "%s" -Dbpf=enabled ;; --disable-bpf) printf "%s" -Dbpf=disabled ;; --enable-brlapi) printf "%s" -Dbrlapi=enabled ;; @@ -124,16 +165,28 @@ _meson_option_parse() { --disable-cfi) printf "%s" -Dcfi=false ;; --enable-cfi-debug) printf "%s" -Dcfi_debug=true ;; --disable-cfi-debug) printf "%s" -Dcfi_debug=false ;; + --enable-cloop) printf "%s" -Dcloop=enabled ;; + --disable-cloop) printf "%s" -Dcloop=disabled ;; --enable-cocoa) printf "%s" -Dcocoa=enabled ;; --disable-cocoa) printf "%s" -Dcocoa=disabled ;; --enable-coreaudio) printf "%s" -Dcoreaudio=enabled ;; --disable-coreaudio) printf "%s" -Dcoreaudio=disabled ;; + --enable-coroutine-pool) printf "%s" -Dcoroutine_pool=true ;; + --disable-coroutine-pool) printf "%s" -Dcoroutine_pool=false ;; + --enable-crypto-afalg) printf "%s" -Dcrypto_afalg=enabled ;; + --disable-crypto-afalg) printf "%s" -Dcrypto_afalg=disabled ;; --enable-curl) printf "%s" -Dcurl=enabled ;; --disable-curl) printf "%s" -Dcurl=disabled ;; --enable-curses) printf "%s" -Dcurses=enabled ;; --disable-curses) printf "%s" -Dcurses=disabled ;; --enable-dbus-display) printf "%s" -Ddbus_display=enabled ;; --disable-dbus-display) printf "%s" -Ddbus_display=disabled ;; + --enable-debug-mutex) printf "%s" -Ddebug_mutex=true ;; + --disable-debug-mutex) printf "%s" -Ddebug_mutex=false ;; + --enable-debug-stack-usage) printf "%s" -Ddebug_stack_usage=true ;; + --disable-debug-stack-usage) printf "%s" -Ddebug_stack_usage=false ;; + --enable-dmg) printf "%s" -Ddmg=enabled ;; + --disable-dmg) printf "%s" -Ddmg=disabled ;; --enable-docs) printf "%s" -Ddocs=enabled ;; --disable-docs) printf "%s" -Ddocs=disabled ;; --enable-dsound) printf "%s" -Ddsound=enabled ;; @@ -155,8 +208,12 @@ _meson_option_parse() { --disable-glusterfs) printf "%s" -Dglusterfs=disabled ;; --enable-gnutls) printf "%s" -Dgnutls=enabled ;; --disable-gnutls) printf "%s" -Dgnutls=disabled ;; + --enable-gprof) printf "%s" -Dgprof=true ;; + --disable-gprof) printf "%s" -Dgprof=false ;; --enable-gtk) printf "%s" -Dgtk=enabled ;; --disable-gtk) printf "%s" -Dgtk=disabled ;; + --enable-guest-agent) printf "%s" -Dguest_agent=enabled ;; + --disable-guest-agent) printf "%s" -Dguest_agent=disabled ;; --enable-guest-agent-msi) printf "%s" -Dguest_agent_msi=enabled ;; --disable-guest-agent-msi) printf "%s" -Dguest_agent_msi=disabled ;; --enable-hax) printf "%s" -Dhax=enabled ;; @@ -191,6 +248,8 @@ _meson_option_parse() { --disable-linux-aio) printf "%s" -Dlinux_aio=disabled ;; --enable-linux-io-uring) printf "%s" -Dlinux_io_uring=enabled ;; --disable-linux-io-uring) printf "%s" -Dlinux_io_uring=disabled ;; + --enable-live-block-migration) printf "%s" -Dlive_block_migration=enabled ;; + --disable-live-block-migration) printf "%s" -Dlive_block_migration=disabled ;; --enable-lzfse) printf "%s" -Dlzfse=enabled ;; --disable-lzfse) printf "%s" -Dlzfse=disabled ;; --enable-lzo) printf "%s" -Dlzo=enabled ;; @@ -198,6 +257,8 @@ _meson_option_parse() { --enable-malloc=*) quote_sh "-Dmalloc=$2" ;; --enable-malloc-trim) printf "%s" -Dmalloc_trim=enabled ;; --disable-malloc-trim) printf "%s" -Dmalloc_trim=disabled ;; + --enable-membarrier) printf "%s" -Dmembarrier=enabled ;; + --disable-membarrier) printf "%s" -Dmembarrier=disabled ;; --enable-mpath) printf "%s" -Dmpath=enabled ;; --disable-mpath) printf "%s" -Dmpath=disabled ;; --enable-multiprocess) printf "%s" -Dmultiprocess=enabled ;; @@ -206,14 +267,32 @@ _meson_option_parse() { --disable-netmap) printf "%s" -Dnetmap=disabled ;; --enable-nettle) printf "%s" -Dnettle=enabled ;; --disable-nettle) printf "%s" -Dnettle=disabled ;; + --enable-numa) printf "%s" -Dnuma=enabled ;; + --disable-numa) printf "%s" -Dnuma=disabled ;; --enable-nvmm) printf "%s" -Dnvmm=enabled ;; --disable-nvmm) printf "%s" -Dnvmm=disabled ;; --enable-oss) printf "%s" -Doss=enabled ;; --disable-oss) printf "%s" -Doss=disabled ;; --enable-pa) printf "%s" -Dpa=enabled ;; --disable-pa) printf "%s" -Dpa=disabled ;; + --enable-parallels) printf "%s" -Dparallels=enabled ;; + --disable-parallels) printf "%s" -Dparallels=disabled ;; + --enable-profiler) printf "%s" -Dprofiler=true ;; + --disable-profiler) printf "%s" -Dprofiler=false ;; + --enable-qcow1) printf "%s" -Dqcow1=enabled ;; + --disable-qcow1) printf "%s" -Dqcow1=disabled ;; + --enable-qed) printf "%s" -Dqed=enabled ;; + --disable-qed) printf "%s" -Dqed=disabled ;; + --enable-qga-vss) printf "%s" -Dqga_vss=enabled ;; + --disable-qga-vss) printf "%s" -Dqga_vss=disabled ;; + --enable-qom-cast-debug) printf "%s" -Dqom_cast_debug=true ;; + --disable-qom-cast-debug) printf "%s" -Dqom_cast_debug=false ;; --enable-rbd) printf "%s" -Drbd=enabled ;; --disable-rbd) printf "%s" -Drbd=disabled ;; + --enable-replication) printf "%s" -Dreplication=enabled ;; + --disable-replication) printf "%s" -Dreplication=disabled ;; + --enable-rng-none) printf "%s" -Drng_none=true ;; + --disable-rng-none) printf "%s" -Drng_none=false ;; --enable-sdl) printf "%s" -Dsdl=enabled ;; --disable-sdl) printf "%s" -Dsdl=disabled ;; --enable-sdl-image) printf "%s" -Dsdl_image=enabled ;; @@ -225,6 +304,8 @@ _meson_option_parse() { --enable-slirp) printf "%s" -Dslirp=enabled ;; --disable-slirp) printf "%s" -Dslirp=disabled ;; --enable-slirp=*) quote_sh "-Dslirp=$2" ;; + --enable-slirp-smbd) printf "%s" -Dslirp_smbd=enabled ;; + --disable-slirp-smbd) printf "%s" -Dslirp_smbd=disabled ;; --enable-smartcard) printf "%s" -Dsmartcard=enabled ;; --disable-smartcard) printf "%s" -Dsmartcard=disabled ;; --enable-snappy) printf "%s" -Dsnappy=enabled ;; @@ -241,6 +322,10 @@ _meson_option_parse() { --disable-tcg) printf "%s" -Dtcg=disabled ;; --enable-tcg-interpreter) printf "%s" -Dtcg_interpreter=true ;; --disable-tcg-interpreter) printf "%s" -Dtcg_interpreter=false ;; + --enable-tools) printf "%s" -Dtools=enabled ;; + --disable-tools) printf "%s" -Dtools=disabled ;; + --enable-tpm) printf "%s" -Dtpm=enabled ;; + --disable-tpm) printf "%s" -Dtpm=disabled ;; --enable-trace-backends=*) quote_sh "-Dtrace_backends=$2" ;; --enable-u2f) printf "%s" -Du2f=enabled ;; --disable-u2f) printf "%s" -Du2f=disabled ;; @@ -248,6 +333,8 @@ _meson_option_parse() { --disable-usb-redir) printf "%s" -Dusb_redir=disabled ;; --enable-vde) printf "%s" -Dvde=enabled ;; --disable-vde) printf "%s" -Dvde=disabled ;; + --enable-vdi) printf "%s" -Dvdi=enabled ;; + --disable-vdi) printf "%s" -Dvdi=disabled ;; --enable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=enabled ;; --disable-vhost-user-blk-server) printf "%s" -Dvhost_user_blk_server=disabled ;; --enable-virglrenderer) printf "%s" -Dvirglrenderer=enabled ;; @@ -266,6 +353,8 @@ _meson_option_parse() { --disable-vnc-sasl) printf "%s" -Dvnc_sasl=disabled ;; --enable-vte) printf "%s" -Dvte=enabled ;; --disable-vte) printf "%s" -Dvte=disabled ;; + --enable-vvfat) printf "%s" -Dvvfat=enabled ;; + --disable-vvfat) printf "%s" -Dvvfat=disabled ;; --enable-whpx) printf "%s" -Dwhpx=enabled ;; --disable-whpx) printf "%s" -Dwhpx=disabled ;; --enable-xen) printf "%s" -Dxen=enabled ;; diff --git a/scripts/switch-timer-api b/scripts/switch-timer-api deleted file mode 100755 index 41736d11dd..0000000000 --- a/scripts/switch-timer-api +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use Getopt::Long; -use FindBin; - -my @legacy = qw(qemu_clock_ptr qemu_get_clock_ns qemu_get_clock_ms qemu_register_clock_reset_notifier qemu_unregister_clock_reset_notifier qemu_new_timer qemu_free_timer qemu_del_timer qemu_mod_timer_ns qemu_mod_timer qemu_run_timers qemu_new_timer_ns qemu_new_timer_us qemu_new_timer_ms); -my $legacyre = '\b('.join('|', @legacy).')\b'; -my $option_git; -my $option_dryrun; -my $option_quiet; -my $option_rtc; -my $suffix=".tmp.$$"; -my @files; -my $getfiles = 'git grep -l -E \'\b((host|rt|vm|rtc)_clock\b|qemu_\w*timer)\' | egrep \'\.[ch]$\' | egrep -v \'qemu-timer\.c$|include/qemu/timer\.h$\''; - -sub Syntax -{ - print STDERR < \$option_dryrun, - "git|g" => \$option_git, - "quiet|q" => \$option_quiet, - "rtc|r" => \$option_rtc, - "help|h" => sub { Syntax(); exit(0); } - )) - { - Syntax(); - die "Bad options"; - } - - if ($#ARGV >=0) - { - @files = @ARGV; - } - else - { - @files = split(/\s+/, `$getfiles`); - } - - foreach my $file (@files) - { - die "Cannot find $file" unless (-f $file && -r $file); - } -} - -sub DoWarn -{ - my $text = shift @_; - my $line = shift @_; - return if ($option_quiet); - chomp ($line); - print STDERR "$text\n"; - print STDERR "$line\n\n"; -} - -sub Process -{ - my $ifn = shift @_; - my $ofn = $ifn.$suffix; - - my $intext; - my $outtext; - my $linenum = 0; - - open my $input, "<", $ifn || die "Cannot open $ifn for read: $!"; - - while (<$input>) - { - my $line = $_; - $intext .= $line; - $linenum++; - - # fix the specific uses - unless ($option_rtc) - { - $line =~ s/\bqemu_new_timer(_[num]s)\s*\((vm_|rt_|host_)clock\b/timer_new$1(XXX_$2clock/g; - $line =~ s/\bqemu_new_timer\s*\((vm_|rt_|host_)clock\b/timer_new(XXX_$1clock/g; - $line =~ s/\bqemu_get_clock(_[num]s)\s*\((vm_|rt_|host_)clock\b/qemu_clock_get$1(XXX_$2clock/g; - } - - # rtc is different - $line =~ s/\bqemu_new_timer(_[num]s)\s*\(rtc_clock\b/timer_new$1(rtc_clock/g; - $line =~ s/\bqemu_new_timer\s*\(rtc_clock\b/timer_new(rtc_clock/g; - $line =~ s/\bqemu_get_clock(_[num]s)\s*\(rtc_clock\b/qemu_clock_get$1(rtc_clock/g; - $line =~ s/\bqemu_register_clock_reset_notifier\s*\(rtc_clock\b/qemu_register_clock_reset_notifier(qemu_clock_ptr(rtc_clock)/g; - - unless ($option_rtc) - { - # fix up comments - $line =~ s/\b(vm_|rt_|host_)clock\b/XXX_$1clock/g if ($line =~ m,^[/ ]+\*,); - - # spurious fprintf error reporting - $line =~ s/: qemu_new_timer_ns failed/: timer_new_ns failed/g; - - # these have just changed name - $line =~ s/\bqemu_mod_timer\b/timer_mod/g; - $line =~ s/\bqemu_mod_timer_(ns|us|ms)\b/timer_mod_$1/g; - $line =~ s/\bqemu_free_timer\b/timer_free/g; - $line =~ s/\bqemu_del_timer\b/timer_del/g; - } - - # fix up rtc_clock - $line =~ s/QEMUClock \*rtc_clock;/QEMUClockType rtc_clock;/g; - $line =~ s/\brtc_clock = (vm_|rt_|host_)clock\b/rtc_clock = XXX_$1clock/g; - - unless ($option_rtc) - { - # replace any more general uses - $line =~ s/\b(vm_|rt_|host_)clock\b/qemu_clock_ptr(XXX_$1clock)/g; - } - - # fix up the place holders - $line =~ s/\bXXX_vm_clock\b/QEMU_CLOCK_VIRTUAL/g; - $line =~ s/\bXXX_rt_clock\b/QEMU_CLOCK_REALTIME/g; - $line =~ s/\bXXX_host_clock\b/QEMU_CLOCK_HOST/g; - - unless ($option_rtc) - { - DoWarn("$ifn:$linenum WARNING: timer $1 not fixed up", $line) if ($line =~ /\b((vm_|rt_|host_)clock)\b/); - DoWarn("$ifn:$linenum WARNING: function $1 not fixed up", $line) if ($line =~ /\b(qemu_new_timer\w+)\b/); - DoWarn("$ifn:$linenum WARNING: legacy function $1 remains", $line) if ($line =~ /$legacyre/o); - } - - $outtext .= $line; - } - - close $input; - - if ($intext ne $outtext) - { - print STDERR "Patching $ifn\n" unless ($option_quiet); - unless ($option_dryrun) - { - open my $output, ">", $ofn || die "Cannot open $ofn for write: $!"; - print $output $outtext; - close $output; - rename ($ofn, $ifn) || die "Cannot rename temp file to $ifn: $!"; - return 1; - } - } - return 0; -} - -sub DoCommit -{ - my $file = shift @_; - open (my $git, "| git commit -F - $file") || die "Cannot run git commit on $file: $!"; - print $git "timers api: use new timer api in $file\n\nConvert $file to use new timer API.\nThis is an automated commit made by scripts/switch-timer-api\n"; - close ($git); -} - -ParseOptions; - -foreach my $file (@files) -{ - my $changed = Process ($file); - DoCommit($file) if ($changed && $option_git); -} diff --git a/softmmu/memory.c b/softmmu/memory.c index 678dc62f06..8060c6de78 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -2790,19 +2790,32 @@ void memory_global_after_dirty_log_sync(void) MEMORY_LISTENER_CALL_GLOBAL(log_global_after_sync, Forward); } +/* + * Dirty track stop flags that are postponed due to VM being stopped. Should + * only be used within vmstate_change hook. + */ +static unsigned int postponed_stop_flags; static VMChangeStateEntry *vmstate_change; +static void memory_global_dirty_log_stop_postponed_run(void); void memory_global_dirty_log_start(unsigned int flags) { - unsigned int old_flags = global_dirty_tracking; - - if (vmstate_change) { - qemu_del_vm_change_state_handler(vmstate_change); - vmstate_change = NULL; - } + unsigned int old_flags; assert(flags && !(flags & (~GLOBAL_DIRTY_MASK))); - assert(!(global_dirty_tracking & flags)); + + if (vmstate_change) { + /* If there is postponed stop(), operate on it first */ + postponed_stop_flags &= ~flags; + memory_global_dirty_log_stop_postponed_run(); + } + + flags &= ~global_dirty_tracking; + if (!flags) { + return; + } + + old_flags = global_dirty_tracking; global_dirty_tracking |= flags; trace_global_dirty_changed(global_dirty_tracking); @@ -2830,29 +2843,45 @@ static void memory_global_dirty_log_do_stop(unsigned int flags) } } +/* + * Execute the postponed dirty log stop operations if there is, then reset + * everything (including the flags and the vmstate change hook). + */ +static void memory_global_dirty_log_stop_postponed_run(void) +{ + /* This must be called with the vmstate handler registered */ + assert(vmstate_change); + + /* Note: postponed_stop_flags can be cleared in log start routine */ + if (postponed_stop_flags) { + memory_global_dirty_log_do_stop(postponed_stop_flags); + postponed_stop_flags = 0; + } + + qemu_del_vm_change_state_handler(vmstate_change); + vmstate_change = NULL; +} + static void memory_vm_change_state_handler(void *opaque, bool running, RunState state) { - unsigned int flags = (unsigned int)(uintptr_t)opaque; if (running) { - memory_global_dirty_log_do_stop(flags); - - if (vmstate_change) { - qemu_del_vm_change_state_handler(vmstate_change); - vmstate_change = NULL; - } + memory_global_dirty_log_stop_postponed_run(); } } void memory_global_dirty_log_stop(unsigned int flags) { if (!runstate_is_running()) { + /* Postpone the dirty log stop, e.g., to when VM starts again */ if (vmstate_change) { - return; + /* Batch with previous postponed flags */ + postponed_stop_flags |= flags; + } else { + postponed_stop_flags = flags; + vmstate_change = qemu_add_vm_change_state_handler( + memory_vm_change_state_handler, NULL); } - vmstate_change = qemu_add_vm_change_state_handler( - memory_vm_change_state_handler, - (void *)(uintptr_t)flags); return; } diff --git a/softmmu/meson.build b/softmmu/meson.build index d8e03018ab..39f766ce7c 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -27,6 +27,9 @@ softmmu_ss.add(files( 'qdev-monitor.c', ), sdl, libpmem, libdaxctl) -softmmu_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c')) +if have_tpm + softmmu_ss.add(files('tpm.c')) +endif + softmmu_ss.add(when: seccomp, if_true: files('qemu-seccomp.c')) softmmu_ss.add(when: fdt, if_true: files('device_tree.c')) diff --git a/softmmu/physmem.c b/softmmu/physmem.c index dddf70edf5..a13289a594 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -23,6 +23,7 @@ #include "qemu/cutils.h" #include "qemu/cacheflush.h" +#include "qemu/madvise.h" #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c index f50026778c..deaf8a4ef5 100644 --- a/softmmu/qemu-seccomp.c +++ b/softmmu/qemu-seccomp.c @@ -38,6 +38,7 @@ struct QemuSeccompSyscall { uint8_t set; uint8_t narg; const struct scmp_arg_cmp *arg_cmp; + uint32_t action; }; const struct scmp_arg_cmp sched_setscheduler_arg[] = { @@ -45,63 +46,223 @@ const struct scmp_arg_cmp sched_setscheduler_arg[] = { { .arg = 1, .op = SCMP_CMP_NE, .datum_a = SCHED_IDLE } }; +/* + * See 'NOTES' in 'man 2 clone' - s390 & cross have 'flags' in + * different position to other architectures + */ +#if defined(HOST_S390X) || defined(HOST_S390) || defined(HOST_CRIS) +#define CLONE_FLAGS_ARG 1 +#else +#define CLONE_FLAGS_ARG 0 +#endif + +#ifndef CLONE_PIDFD +# define CLONE_PIDFD 0x00001000 +#endif + +#define REQUIRE_CLONE_FLAG(flag) \ + const struct scmp_arg_cmp clone_arg ## flag[] = { \ + { .arg = CLONE_FLAGS_ARG, \ + .op = SCMP_CMP_MASKED_EQ, \ + .datum_a = flag, .datum_b = 0 } } + +#define FORBID_CLONE_FLAG(flag) \ + const struct scmp_arg_cmp clone_arg ## flag[] = { \ + { .arg = CLONE_FLAGS_ARG, \ + .op = SCMP_CMP_MASKED_EQ, \ + .datum_a = flag, .datum_b = flag } } + +#define RULE_CLONE_FLAG(flag) \ + { SCMP_SYS(clone), QEMU_SECCOMP_SET_SPAWN, \ + ARRAY_SIZE(clone_arg ## flag), clone_arg ## flag, SCMP_ACT_TRAP } + +/* If no CLONE_* flags are set, except CSIGNAL, deny */ +const struct scmp_arg_cmp clone_arg_none[] = { + { .arg = CLONE_FLAGS_ARG, + .op = SCMP_CMP_MASKED_EQ, + .datum_a = ~(CSIGNAL), .datum_b = 0 } +}; + +/* + * pthread_create should always set all of these. + */ +REQUIRE_CLONE_FLAG(CLONE_VM); +REQUIRE_CLONE_FLAG(CLONE_FS); +REQUIRE_CLONE_FLAG(CLONE_FILES); +REQUIRE_CLONE_FLAG(CLONE_SIGHAND); +REQUIRE_CLONE_FLAG(CLONE_THREAD); +REQUIRE_CLONE_FLAG(CLONE_SYSVSEM); +REQUIRE_CLONE_FLAG(CLONE_SETTLS); +REQUIRE_CLONE_FLAG(CLONE_PARENT_SETTID); +REQUIRE_CLONE_FLAG(CLONE_CHILD_CLEARTID); +/* + * Musl sets this in pthread_create too, but it is + * obsolete and harmless since its behaviour is + * subsumed under CLONE_THREAD + */ +/*REQUIRE_CLONE_FLAG(CLONE_DETACHED);*/ + + +/* + * These all indicate an attempt to spawn a process + * instead of a thread, or other undesirable scenarios + */ +FORBID_CLONE_FLAG(CLONE_PIDFD); +FORBID_CLONE_FLAG(CLONE_PTRACE); +FORBID_CLONE_FLAG(CLONE_VFORK); +FORBID_CLONE_FLAG(CLONE_PARENT); +FORBID_CLONE_FLAG(CLONE_NEWNS); +FORBID_CLONE_FLAG(CLONE_UNTRACED); +FORBID_CLONE_FLAG(CLONE_NEWCGROUP); +FORBID_CLONE_FLAG(CLONE_NEWUTS); +FORBID_CLONE_FLAG(CLONE_NEWIPC); +FORBID_CLONE_FLAG(CLONE_NEWUSER); +FORBID_CLONE_FLAG(CLONE_NEWPID); +FORBID_CLONE_FLAG(CLONE_NEWNET); +FORBID_CLONE_FLAG(CLONE_IO); + + static const struct QemuSeccompSyscall denylist[] = { /* default set of syscalls that should get blocked */ - { SCMP_SYS(reboot), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(swapon), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(swapoff), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(syslog), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(mount), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(umount), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(kexec_load), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(afs_syscall), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(break), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(ftime), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(getpmsg), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(gtty), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(lock), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(mpx), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(prof), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(profil), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(putpmsg), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(security), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(stty), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(tuxcall), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(ulimit), QEMU_SECCOMP_SET_DEFAULT }, - { SCMP_SYS(vserver), QEMU_SECCOMP_SET_DEFAULT }, + { SCMP_SYS(reboot), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(swapon), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(swapoff), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(syslog), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(mount), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(umount), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(kexec_load), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(afs_syscall), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(break), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(ftime), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(getpmsg), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(gtty), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(lock), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(mpx), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(prof), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(profil), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(putpmsg), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(security), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(stty), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(tuxcall), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(ulimit), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(vserver), QEMU_SECCOMP_SET_DEFAULT, + 0, NULL, SCMP_ACT_TRAP }, /* obsolete */ - { SCMP_SYS(readdir), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(_sysctl), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(bdflush), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(create_module), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(get_kernel_syms), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(query_module), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(sgetmask), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(ssetmask), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(sysfs), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(uselib), QEMU_SECCOMP_SET_OBSOLETE }, - { SCMP_SYS(ustat), QEMU_SECCOMP_SET_OBSOLETE }, + { SCMP_SYS(readdir), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(_sysctl), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(bdflush), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(create_module), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(get_kernel_syms), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(query_module), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(sgetmask), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(ssetmask), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(sysfs), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(uselib), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(ustat), QEMU_SECCOMP_SET_OBSOLETE, + 0, NULL, SCMP_ACT_TRAP }, /* privileged */ - { SCMP_SYS(setuid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setgid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setpgid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setsid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setreuid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setregid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setresuid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setresgid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setfsuid), QEMU_SECCOMP_SET_PRIVILEGED }, - { SCMP_SYS(setfsgid), QEMU_SECCOMP_SET_PRIVILEGED }, + { SCMP_SYS(setuid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setgid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setpgid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setsid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setreuid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setregid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setresuid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setresgid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setfsuid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(setfsgid), QEMU_SECCOMP_SET_PRIVILEGED, + 0, NULL, SCMP_ACT_TRAP }, /* spawn */ - { SCMP_SYS(fork), QEMU_SECCOMP_SET_SPAWN }, - { SCMP_SYS(vfork), QEMU_SECCOMP_SET_SPAWN }, - { SCMP_SYS(execve), QEMU_SECCOMP_SET_SPAWN }, + { SCMP_SYS(fork), QEMU_SECCOMP_SET_SPAWN, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(vfork), QEMU_SECCOMP_SET_SPAWN, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(execve), QEMU_SECCOMP_SET_SPAWN, + 0, NULL, SCMP_ACT_TRAP }, + { SCMP_SYS(clone), QEMU_SECCOMP_SET_SPAWN, + ARRAY_SIZE(clone_arg_none), clone_arg_none, SCMP_ACT_TRAP }, + RULE_CLONE_FLAG(CLONE_VM), + RULE_CLONE_FLAG(CLONE_FS), + RULE_CLONE_FLAG(CLONE_FILES), + RULE_CLONE_FLAG(CLONE_SIGHAND), + RULE_CLONE_FLAG(CLONE_THREAD), + RULE_CLONE_FLAG(CLONE_SYSVSEM), + RULE_CLONE_FLAG(CLONE_SETTLS), + RULE_CLONE_FLAG(CLONE_PARENT_SETTID), + RULE_CLONE_FLAG(CLONE_CHILD_CLEARTID), + /*RULE_CLONE_FLAG(CLONE_DETACHED),*/ + RULE_CLONE_FLAG(CLONE_PIDFD), + RULE_CLONE_FLAG(CLONE_PTRACE), + RULE_CLONE_FLAG(CLONE_VFORK), + RULE_CLONE_FLAG(CLONE_PARENT), + RULE_CLONE_FLAG(CLONE_NEWNS), + RULE_CLONE_FLAG(CLONE_UNTRACED), + RULE_CLONE_FLAG(CLONE_NEWCGROUP), + RULE_CLONE_FLAG(CLONE_NEWUTS), + RULE_CLONE_FLAG(CLONE_NEWIPC), + RULE_CLONE_FLAG(CLONE_NEWUSER), + RULE_CLONE_FLAG(CLONE_NEWPID), + RULE_CLONE_FLAG(CLONE_NEWNET), + RULE_CLONE_FLAG(CLONE_IO), +#ifdef __SNR_clone3 + { SCMP_SYS(clone3), QEMU_SECCOMP_SET_SPAWN, + 0, NULL, SCMP_ACT_ERRNO(ENOSYS) }, +#endif +#ifdef __SNR_execveat + { SCMP_SYS(execveat), QEMU_SECCOMP_SET_SPAWN }, +#endif + { SCMP_SYS(setns), QEMU_SECCOMP_SET_SPAWN }, + { SCMP_SYS(unshare), QEMU_SECCOMP_SET_SPAWN }, /* resource control */ - { SCMP_SYS(setpriority), QEMU_SECCOMP_SET_RESOURCECTL }, - { SCMP_SYS(sched_setparam), QEMU_SECCOMP_SET_RESOURCECTL }, + { SCMP_SYS(setpriority), QEMU_SECCOMP_SET_RESOURCECTL, + 0, NULL, SCMP_ACT_ERRNO(EPERM) }, + { SCMP_SYS(sched_setparam), QEMU_SECCOMP_SET_RESOURCECTL, + 0, NULL, SCMP_ACT_ERRNO(EPERM) }, { SCMP_SYS(sched_setscheduler), QEMU_SECCOMP_SET_RESOURCECTL, - ARRAY_SIZE(sched_setscheduler_arg), sched_setscheduler_arg }, - { SCMP_SYS(sched_setaffinity), QEMU_SECCOMP_SET_RESOURCECTL }, + ARRAY_SIZE(sched_setscheduler_arg), sched_setscheduler_arg, + SCMP_ACT_ERRNO(EPERM) }, + { SCMP_SYS(sched_setaffinity), QEMU_SECCOMP_SET_RESOURCECTL, + 0, NULL, SCMP_ACT_ERRNO(EPERM) }, }; static inline __attribute__((unused)) int @@ -115,15 +276,11 @@ qemu_seccomp(unsigned int operation, unsigned int flags, void *args) #endif } -static uint32_t qemu_seccomp_get_action(int set) +static uint32_t qemu_seccomp_update_action(uint32_t action) { - switch (set) { - case QEMU_SECCOMP_SET_DEFAULT: - case QEMU_SECCOMP_SET_OBSOLETE: - case QEMU_SECCOMP_SET_PRIVILEGED: - case QEMU_SECCOMP_SET_SPAWN: { #if defined(SECCOMP_GET_ACTION_AVAIL) && defined(SCMP_ACT_KILL_PROCESS) && \ defined(SECCOMP_RET_KILL_PROCESS) + if (action == SCMP_ACT_TRAP) { static int kill_process = -1; if (kill_process == -1) { uint32_t action = SECCOMP_RET_KILL_PROCESS; @@ -137,16 +294,9 @@ static uint32_t qemu_seccomp_get_action(int set) if (kill_process == 1) { return SCMP_ACT_KILL_PROCESS; } + } #endif - return SCMP_ACT_TRAP; - } - - case QEMU_SECCOMP_SET_RESOURCECTL: - return SCMP_ACT_ERRNO(EPERM); - - default: - g_assert_not_reached(); - } + return action; } @@ -175,7 +325,7 @@ static int seccomp_start(uint32_t seccomp_opts, Error **errp) continue; } - action = qemu_seccomp_get_action(denylist[i].set); + action = qemu_seccomp_update_action(denylist[i].action); rc = seccomp_rule_add_array(ctx, action, denylist[i].num, denylist[i].narg, denylist[i].arg_cmp); if (rc < 0) { diff --git a/softmmu/qtest.c b/softmmu/qtest.c index 72751e1fd8..8b7cb6aa8e 100644 --- a/softmmu/qtest.c +++ b/softmmu/qtest.c @@ -19,6 +19,7 @@ #include "chardev/char-fe.h" #include "exec/ioport.h" #include "exec/memory.h" +#include "hw/qdev-core.h" #include "hw/irq.h" #include "qemu/accel.h" #include "sysemu/cpu-timers.h" diff --git a/softmmu/runstate.c b/softmmu/runstate.c index 10d9b7365a..e0d869b21a 100644 --- a/softmmu/runstate.c +++ b/softmmu/runstate.c @@ -30,7 +30,6 @@ #include "crypto/cipher.h" #include "crypto/init.h" #include "exec/cpu-common.h" -#include "exec/exec-all.h" #include "exec/gdbstub.h" #include "hw/boards.h" #include "migration/misc.h" @@ -43,7 +42,9 @@ #include "qapi/qapi-events-run-state.h" #include "qemu-common.h" #include "qemu/error-report.h" +#include "qemu/log.h" #include "qemu/job.h" +#include "qemu/log.h" #include "qemu/module.h" #include "qemu/plugin.h" #include "qemu/sockets.h" diff --git a/softmmu/vl.c b/softmmu/vl.c index 5e1b35ba48..1fe028800f 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -36,6 +36,7 @@ #include "qemu-version.h" #include "qemu/cutils.h" #include "qemu/help_option.h" +#include "qemu/hw-version.h" #include "qemu/uuid.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" diff --git a/target/alpha/helper.c b/target/alpha/helper.c index b7e7f73b15..dcaa2d03ad 100644 --- a/target/alpha/helper.c +++ b/target/alpha/helper.c @@ -18,7 +18,7 @@ */ #include "qemu/osdep.h" - +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "fpu/softfloat-types.h" diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5a9c02a256..c085dc10ee 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/qemu-print.h" +#include "qemu/timer.h" #include "qemu-common.h" #include "target/arm/idau.h" #include "qemu/module.h" @@ -39,7 +40,6 @@ #include "sysemu/tcg.h" #include "sysemu/hw_accel.h" #include "kvm_arm.h" -#include "hvf_arm.h" #include "disas/capstone.h" #include "fpu/softfloat.h" @@ -2079,31 +2079,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) #endif /* CONFIG_TCG */ } -#if defined(CONFIG_KVM) || defined(CONFIG_HVF) -static void arm_host_initfn(Object *obj) -{ - ARMCPU *cpu = ARM_CPU(obj); - -#ifdef CONFIG_KVM - kvm_arm_set_cpu_features_from_host(cpu); - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - aarch64_add_sve_properties(obj); - aarch64_add_pauth_properties(obj); - } -#else - hvf_arm_set_cpu_features_from_host(cpu); -#endif - arm_cpu_post_init(obj); -} - -static const TypeInfo host_arm_cpu_type_info = { - .name = TYPE_ARM_HOST_CPU, - .parent = TYPE_AARCH64_CPU, - .instance_init = arm_host_initfn, -}; - -#endif - static void arm_cpu_instance_init(Object *obj) { ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); @@ -2151,10 +2126,6 @@ static const TypeInfo arm_cpu_type_info = { static void arm_cpu_register_types(void) { type_register_static(&arm_cpu_type_info); - -#if defined(CONFIG_KVM) || defined(CONFIG_HVF) - type_register_static(&host_arm_cpu_type_info); -#endif } type_init(arm_cpu_register_types) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 8786be7783..1171ab16b9 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -29,7 +29,9 @@ #include "hw/loader.h" #endif #include "sysemu/kvm.h" +#include "sysemu/hvf.h" #include "kvm_arm.h" +#include "hvf_arm.h" #include "qapi/visitor.h" #include "hw/qdev-properties.h" @@ -631,9 +633,10 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) uint64_t t; /* Exit early if PAuth is enabled, and fall through to disable it */ - if (kvm_enabled() && cpu->prop_pauth) { + if ((kvm_enabled() || hvf_enabled()) && cpu->prop_pauth) { if (!cpu_isar_feature(aa64_pauth, cpu)) { - error_setg(errp, "'pauth' feature not supported by KVM on this host"); + error_setg(errp, "'pauth' feature not supported by %s on this host", + kvm_enabled() ? "KVM" : "hvf"); } return; @@ -670,10 +673,14 @@ void aarch64_add_pauth_properties(Object *obj) /* Default to PAUTH on, with the architected algorithm on TCG. */ qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property); - if (kvm_enabled()) { + if (kvm_enabled() || hvf_enabled()) { /* * Mirror PAuth support from the probed sysregs back into the - * property for KVM. Is it just a bit backward? Yes it is! + * property for KVM or hvf. Is it just a bit backward? Yes it is! + * Note that prop_pauth is true whether the host CPU supports the + * architected QARMA5 algorithm or the IMPDEF one. We don't + * provide the separate pauth-impdef property for KVM or hvf, + * only for TCG. */ cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu); } else { @@ -681,6 +688,24 @@ void aarch64_add_pauth_properties(Object *obj) } } +static void aarch64_host_initfn(Object *obj) +{ +#if defined(CONFIG_KVM) + ARMCPU *cpu = ARM_CPU(obj); + kvm_arm_set_cpu_features_from_host(cpu); + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + aarch64_add_sve_properties(obj); + aarch64_add_pauth_properties(obj); + } +#elif defined(CONFIG_HVF) + ARMCPU *cpu = ARM_CPU(obj); + hvf_arm_set_cpu_features_from_host(cpu); + aarch64_add_pauth_properties(obj); +#else + g_assert_not_reached(); +#endif +} + /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); * otherwise, a CPU with as many features enabled as our emulation supports. * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; @@ -689,174 +714,179 @@ void aarch64_add_pauth_properties(Object *obj) static void aarch64_max_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); + uint64_t t; + uint32_t u; - if (kvm_enabled()) { - kvm_arm_set_cpu_features_from_host(cpu); - } else { - uint64_t t; - uint32_t u; - aarch64_a57_initfn(obj); + if (kvm_enabled() || hvf_enabled()) { + /* With KVM or HVF, '-cpu max' is identical to '-cpu host' */ + aarch64_host_initfn(obj); + return; + } - /* - * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real - * one and try to apply errata workarounds or use impdef features we - * don't provide. - * An IMPLEMENTER field of 0 means "reserved for software use"; - * ARCHITECTURE must be 0xf indicating "v7 or later, check ID registers - * to see which features are present"; - * the VARIANT, PARTNUM and REVISION fields are all implementation - * defined and we choose to define PARTNUM just in case guest - * code needs to distinguish this QEMU CPU from other software - * implementations, though this shouldn't be needed. - */ - t = FIELD_DP64(0, MIDR_EL1, IMPLEMENTER, 0); - t = FIELD_DP64(t, MIDR_EL1, ARCHITECTURE, 0xf); - t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 'Q'); - t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0); - t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); - cpu->midr = t; + /* '-cpu max' for TCG: we currently do this as "A57 with extra things" */ - t = cpu->isar.id_aa64isar0; - t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ - t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); - t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); - t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ - t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ - t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); - cpu->isar.id_aa64isar0 = t; + aarch64_a57_initfn(obj); - t = cpu->isar.id_aa64isar1; - t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); - t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ - t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); - cpu->isar.id_aa64isar1 = t; + /* + * Reset MIDR so the guest doesn't mistake our 'max' CPU type for a real + * one and try to apply errata workarounds or use impdef features we + * don't provide. + * An IMPLEMENTER field of 0 means "reserved for software use"; + * ARCHITECTURE must be 0xf indicating "v7 or later, check ID registers + * to see which features are present"; + * the VARIANT, PARTNUM and REVISION fields are all implementation + * defined and we choose to define PARTNUM just in case guest + * code needs to distinguish this QEMU CPU from other software + * implementations, though this shouldn't be needed. + */ + t = FIELD_DP64(0, MIDR_EL1, IMPLEMENTER, 0); + t = FIELD_DP64(t, MIDR_EL1, ARCHITECTURE, 0xf); + t = FIELD_DP64(t, MIDR_EL1, PARTNUM, 'Q'); + t = FIELD_DP64(t, MIDR_EL1, VARIANT, 0); + t = FIELD_DP64(t, MIDR_EL1, REVISION, 0); + cpu->midr = t; - t = cpu->isar.id_aa64pfr0; - t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); - t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); - t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); - t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); - cpu->isar.id_aa64pfr0 = t; + t = cpu->isar.id_aa64isar0; + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* AES + PMULL */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* SHA512 */ + t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); + t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */ + t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); + cpu->isar.id_aa64isar0 = t; - t = cpu->isar.id_aa64pfr1; - t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); - t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); - /* - * Begin with full support for MTE. This will be downgraded to MTE=0 - * during realize if the board provides no tag memory, much like - * we do for EL2 with the virtualization=on property. - */ - t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); - cpu->isar.id_aa64pfr1 = t; + t = cpu->isar.id_aa64isar1; + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); + cpu->isar.id_aa64isar1 = t; - t = cpu->isar.id_aa64mmfr0; - t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 5); /* PARange: 48 bits */ - cpu->isar.id_aa64mmfr0 = t; + t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); + t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); + cpu->isar.id_aa64pfr0 = t; - t = cpu->isar.id_aa64mmfr1; - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); - t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ - t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ - t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */ - cpu->isar.id_aa64mmfr1 = t; + t = cpu->isar.id_aa64pfr1; + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); + t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); + /* + * Begin with full support for MTE. This will be downgraded to MTE=0 + * during realize if the board provides no tag memory, much like + * we do for EL2 with the virtualization=on property. + */ + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); + cpu->isar.id_aa64pfr1 = t; - t = cpu->isar.id_aa64mmfr2; - t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); - t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ - t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */ - cpu->isar.id_aa64mmfr2 = t; + t = cpu->isar.id_aa64mmfr0; + t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 5); /* PARange: 48 bits */ + cpu->isar.id_aa64mmfr0 = t; - t = cpu->isar.id_aa64zfr0; - t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* PMULL */ - t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); - t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); - cpu->isar.id_aa64zfr0 = t; + t = cpu->isar.id_aa64mmfr1; + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */ + t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); + t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); + t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */ + t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */ + cpu->isar.id_aa64mmfr1 = t; - /* Replicate the same data to the 32-bit id registers. */ - u = cpu->isar.id_isar5; - u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ - u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); - u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); - u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); - u = FIELD_DP32(u, ID_ISAR5, RDM, 1); - u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); - cpu->isar.id_isar5 = u; + t = cpu->isar.id_aa64mmfr2; + t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ + t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */ + cpu->isar.id_aa64mmfr2 = t; - u = cpu->isar.id_isar6; - u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); - u = FIELD_DP32(u, ID_ISAR6, DP, 1); - u = FIELD_DP32(u, ID_ISAR6, FHM, 1); - u = FIELD_DP32(u, ID_ISAR6, SB, 1); - u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); - u = FIELD_DP32(u, ID_ISAR6, BF16, 1); - u = FIELD_DP32(u, ID_ISAR6, I8MM, 1); - cpu->isar.id_isar6 = u; + t = cpu->isar.id_aa64zfr0; + t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* PMULL */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); + cpu->isar.id_aa64zfr0 = t; - u = cpu->isar.id_pfr0; - u = FIELD_DP32(u, ID_PFR0, DIT, 1); - cpu->isar.id_pfr0 = u; + /* Replicate the same data to the 32-bit id registers. */ + u = cpu->isar.id_isar5; + u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */ + u = FIELD_DP32(u, ID_ISAR5, SHA1, 1); + u = FIELD_DP32(u, ID_ISAR5, SHA2, 1); + u = FIELD_DP32(u, ID_ISAR5, CRC32, 1); + u = FIELD_DP32(u, ID_ISAR5, RDM, 1); + u = FIELD_DP32(u, ID_ISAR5, VCMA, 1); + cpu->isar.id_isar5 = u; - u = cpu->isar.id_pfr2; - u = FIELD_DP32(u, ID_PFR2, SSBS, 1); - cpu->isar.id_pfr2 = u; + u = cpu->isar.id_isar6; + u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); + u = FIELD_DP32(u, ID_ISAR6, DP, 1); + u = FIELD_DP32(u, ID_ISAR6, FHM, 1); + u = FIELD_DP32(u, ID_ISAR6, SB, 1); + u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1); + u = FIELD_DP32(u, ID_ISAR6, BF16, 1); + u = FIELD_DP32(u, ID_ISAR6, I8MM, 1); + cpu->isar.id_isar6 = u; - u = cpu->isar.id_mmfr3; - u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ - cpu->isar.id_mmfr3 = u; + u = cpu->isar.id_pfr0; + u = FIELD_DP32(u, ID_PFR0, DIT, 1); + cpu->isar.id_pfr0 = u; - u = cpu->isar.id_mmfr4; - u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ - u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */ - u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ - cpu->isar.id_mmfr4 = u; + u = cpu->isar.id_pfr2; + u = FIELD_DP32(u, ID_PFR2, SSBS, 1); + cpu->isar.id_pfr2 = u; - t = cpu->isar.id_aa64dfr0; - t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ - cpu->isar.id_aa64dfr0 = t; + u = cpu->isar.id_mmfr3; + u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */ + cpu->isar.id_mmfr3 = u; - u = cpu->isar.id_dfr0; - u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ - cpu->isar.id_dfr0 = u; + u = cpu->isar.id_mmfr4; + u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ + u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */ + u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */ + cpu->isar.id_mmfr4 = u; - u = cpu->isar.mvfr1; - u = FIELD_DP32(u, MVFR1, FPHP, 3); /* v8.2-FP16 */ - u = FIELD_DP32(u, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ - cpu->isar.mvfr1 = u; + t = cpu->isar.id_aa64dfr0; + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 5); /* v8.4-PMU */ + cpu->isar.id_aa64dfr0 = t; + + u = cpu->isar.id_dfr0; + u = FIELD_DP32(u, ID_DFR0, PERFMON, 5); /* v8.4-PMU */ + cpu->isar.id_dfr0 = u; + + u = cpu->isar.mvfr1; + u = FIELD_DP32(u, MVFR1, FPHP, 3); /* v8.2-FP16 */ + u = FIELD_DP32(u, MVFR1, SIMDHP, 2); /* v8.2-FP16 */ + cpu->isar.mvfr1 = u; #ifdef CONFIG_USER_ONLY - /* For usermode -cpu max we can use a larger and more efficient DCZ - * blocksize since we don't have to follow what the hardware does. - */ - cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ - cpu->dcz_blocksize = 7; /* 512 bytes */ + /* + * For usermode -cpu max we can use a larger and more efficient DCZ + * blocksize since we don't have to follow what the hardware does. + */ + cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ + cpu->dcz_blocksize = 7; /* 512 bytes */ #endif - bitmap_fill(cpu->sve_vq_supported, ARM_MAX_VQ); - } + bitmap_fill(cpu->sve_vq_supported, ARM_MAX_VQ); aarch64_add_pauth_properties(obj); aarch64_add_sve_properties(obj); @@ -917,6 +947,9 @@ static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, +#if defined(CONFIG_KVM) || defined(CONFIG_HVF) + { .name = "host", .initfn = aarch64_host_initfn }, +#endif }; static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp) diff --git a/target/arm/helper.c b/target/arm/helper.c index b5f80988c9..7bf50fdd76 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "qemu/log.h" #include "target/arm/idau.h" #include "trace.h" #include "cpu.h" @@ -15,6 +16,7 @@ #include "exec/helper-proto.h" #include "qemu/host-utils.h" #include "qemu/main-loop.h" +#include "qemu/timer.h" #include "qemu/bitops.h" #include "qemu/crc32c.h" #include "qemu/qemu-print.h" diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 0dc96560d3..4d4ddab348 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -35,9 +35,34 @@ ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2) #define PL1_WRITE_MASK 0x4 +#define SYSREG_OP0_SHIFT 20 +#define SYSREG_OP0_MASK 0x3 +#define SYSREG_OP0(sysreg) ((sysreg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK) +#define SYSREG_OP1_SHIFT 14 +#define SYSREG_OP1_MASK 0x7 +#define SYSREG_OP1(sysreg) ((sysreg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK) +#define SYSREG_CRN_SHIFT 10 +#define SYSREG_CRN_MASK 0xf +#define SYSREG_CRN(sysreg) ((sysreg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK) +#define SYSREG_CRM_SHIFT 1 +#define SYSREG_CRM_MASK 0xf +#define SYSREG_CRM(sysreg) ((sysreg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK) +#define SYSREG_OP2_SHIFT 17 +#define SYSREG_OP2_MASK 0x7 +#define SYSREG_OP2(sysreg) ((sysreg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK) + #define SYSREG(op0, op1, crn, crm, op2) \ - ((op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (crm << 1)) -#define SYSREG_MASK SYSREG(0x3, 0x7, 0xf, 0xf, 0x7) + ((op0 << SYSREG_OP0_SHIFT) | \ + (op1 << SYSREG_OP1_SHIFT) | \ + (crn << SYSREG_CRN_SHIFT) | \ + (crm << SYSREG_CRM_SHIFT) | \ + (op2 << SYSREG_OP2_SHIFT)) +#define SYSREG_MASK \ + SYSREG(SYSREG_OP0_MASK, \ + SYSREG_OP1_MASK, \ + SYSREG_CRN_MASK, \ + SYSREG_CRM_MASK, \ + SYSREG_OP2_MASK) #define SYSREG_OSLAR_EL1 SYSREG(2, 0, 1, 0, 4) #define SYSREG_OSLSR_EL1 SYSREG(2, 0, 1, 1, 4) #define SYSREG_OSDLR_EL1 SYSREG(2, 0, 1, 3, 4) @@ -729,6 +754,15 @@ static bool hvf_handle_psci_call(CPUState *cpu) return true; } +static bool is_id_sysreg(uint32_t reg) +{ + return SYSREG_OP0(reg) == 3 && + SYSREG_OP1(reg) == 0 && + SYSREG_CRN(reg) == 0 && + SYSREG_CRM(reg) >= 1 && + SYSREG_CRM(reg) < 8; +} + static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) { ARMCPU *arm_cpu = ARM_CPU(cpu); @@ -781,23 +815,28 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) /* Dummy register */ break; default: + if (is_id_sysreg(reg)) { + /* ID system registers read as RES0 */ + val = 0; + break; + } cpu_synchronize_state(cpu); trace_hvf_unhandled_sysreg_read(env->pc, reg, - (reg >> 20) & 0x3, - (reg >> 14) & 0x7, - (reg >> 10) & 0xf, - (reg >> 1) & 0xf, - (reg >> 17) & 0x7); + SYSREG_OP0(reg), + SYSREG_OP1(reg), + SYSREG_CRN(reg), + SYSREG_CRM(reg), + SYSREG_OP2(reg)); hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); return 1; } trace_hvf_sysreg_read(reg, - (reg >> 20) & 0x3, - (reg >> 14) & 0x7, - (reg >> 10) & 0xf, - (reg >> 1) & 0xf, - (reg >> 17) & 0x7, + SYSREG_OP0(reg), + SYSREG_OP1(reg), + SYSREG_CRN(reg), + SYSREG_CRM(reg), + SYSREG_OP2(reg), val); hvf_set_reg(cpu, rt, val); @@ -886,11 +925,11 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) CPUARMState *env = &arm_cpu->env; trace_hvf_sysreg_write(reg, - (reg >> 20) & 0x3, - (reg >> 14) & 0x7, - (reg >> 10) & 0xf, - (reg >> 1) & 0xf, - (reg >> 17) & 0x7, + SYSREG_OP0(reg), + SYSREG_OP1(reg), + SYSREG_CRN(reg), + SYSREG_CRM(reg), + SYSREG_OP2(reg), val); switch (reg) { @@ -960,11 +999,11 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) default: cpu_synchronize_state(cpu); trace_hvf_unhandled_sysreg_write(env->pc, reg, - (reg >> 20) & 0x3, - (reg >> 14) & 0x7, - (reg >> 10) & 0xf, - (reg >> 1) & 0xf, - (reg >> 17) & 0x7); + SYSREG_OP0(reg), + SYSREG_OP1(reg), + SYSREG_CRN(reg), + SYSREG_CRM(reg), + SYSREG_OP2(reg)); hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); return 1; } diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index b11e927df1..648a3b3fc1 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -19,6 +19,7 @@ #include "qemu/bitops.h" #include "qemu/crc32c.h" #include "qemu/qemu-print.h" +#include "qemu/log.h" #include "exec/exec-all.h" #include /* For crc32 */ #include "semihosting/semihost.h" diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index e09b7e46a2..d11a8c70d0 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "internals.h" #include "exec/exec-all.h" diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h index 9fa6989c18..14e5b3ce72 100644 --- a/target/avr/cpu-qom.h +++ b/target/avr/cpu-qom.h @@ -33,7 +33,6 @@ OBJECT_DECLARE_TYPE(AVRCPU, AVRCPUClass, * AVRCPUClass: * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. - * @vr: Version Register value. * * A AVR CPU model. */ diff --git a/target/avr/helper.c b/target/avr/helper.c index 981c29da45..c27f702901 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/core/tcg-cpu-ops.h" #include "exec/exec-all.h" diff --git a/target/cris/helper.c b/target/cris/helper.c index a0d6ecdcd3..91e4aeb178 100644 --- a/target/cris/helper.c +++ b/target/cris/helper.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/core/tcg-cpu-ops.h" #include "mmu.h" diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index 82ac3042ab..b1bfadc3f5 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -18,6 +18,8 @@ #ifndef HEXAGON_INTERNAL_H #define HEXAGON_INTERNAL_H +#include "qemu/log.h" + /* * Change HEX_DEBUG to 1 to turn on debugging output */ diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index fccfb94340..a245172827 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -19,6 +19,7 @@ #define HEXAGON_TRANSLATE_H #include "qemu/bitmap.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/translator.h" #include "tcg/tcg-op.h" diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 37b763fca0..5f46ba801e 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/qemu-print.h" +#include "qemu/timer.h" #include "cpu.h" #include "qemu/module.h" #include "exec/exec-all.h" diff --git a/target/hppa/helper.c b/target/hppa/helper.c index 1ccff5765a..e2758d8df3 100644 --- a/target/hppa/helper.c +++ b/target/hppa/helper.c @@ -18,7 +18,7 @@ */ #include "qemu/osdep.h" - +#include "qemu/log.h" #include "cpu.h" #include "fpu/softfloat.h" #include "exec/exec-all.h" diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index bf07445cd1..5046cc8f9d 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index b0dec4ebf4..2810361be0 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" diff --git a/target/i386/cpu.c b/target/i386/cpu.c index aa9e636800..6c7ef1099b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -21,6 +21,7 @@ #include "qemu/units.h" #include "qemu/cutils.h" #include "qemu/qemu-print.h" +#include "qemu/hw-version.h" #include "cpu.h" #include "tcg/helper-tcg.h" #include "sysemu/reset.h" @@ -645,7 +646,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, CPUID_7_0_EBX_RDSEED */ -#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | \ +#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) #define TCG_7_0_EDX_FEATURES 0 diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 9911d7c871..e69ab5dd78 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -167,6 +167,7 @@ typedef enum X86Seg { #define HF_IOBPT_SHIFT 24 /* an io breakpoint enabled */ #define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */ #define HF_MPX_IU_SHIFT 26 /* BND registers in-use */ +#define HF_UMIP_SHIFT 27 /* CR4.UMIP */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) @@ -192,6 +193,7 @@ typedef enum X86Seg { #define HF_IOBPT_MASK (1 << HF_IOBPT_SHIFT) #define HF_MPX_EN_MASK (1 << HF_MPX_EN_SHIFT) #define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT) +#define HF_UMIP_MASK (1 << HF_UMIP_SHIFT) /* hflags2 */ @@ -258,7 +260,7 @@ typedef enum X86Seg { (~(target_ulong)(CR4_VME_MASK | CR4_PVI_MASK | CR4_TSD_MASK \ | CR4_DE_MASK | CR4_PSE_MASK | CR4_PAE_MASK \ | CR4_MCE_MASK | CR4_PGE_MASK | CR4_PCE_MASK \ - | CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK |CR4_UMIP_MASK \ + | CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK | CR4_UMIP_MASK \ | CR4_LA57_MASK \ | CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \ | CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK)) diff --git a/target/i386/helper.c b/target/i386/helper.c index 533b29cb91..fa409e9c44 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -27,6 +27,7 @@ #include "sysemu/hw_accel.h" #include "monitor/monitor.h" #endif +#include "qemu/log.h" void cpu_sync_bndcs_hflags(CPUX86State *env) { @@ -174,7 +175,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) } /* Clear bits we're going to recompute. */ - hflags = env->hflags & ~(HF_OSFXSR_MASK | HF_SMAP_MASK); + hflags = env->hflags & ~(HF_OSFXSR_MASK | HF_SMAP_MASK | HF_UMIP_MASK); /* SSE handling */ if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) { @@ -190,6 +191,12 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) if (new_cr4 & CR4_SMAP_MASK) { hflags |= HF_SMAP_MASK; } + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_UMIP)) { + new_cr4 &= ~CR4_UMIP_MASK; + } + if (new_cr4 & CR4_UMIP_MASK) { + hflags |= HF_UMIP_MASK; + } if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) { new_cr4 &= ~CR4_PKE_MASK; diff --git a/target/i386/tcg/int_helper.c b/target/i386/tcg/int_helper.c index 87fa7280ee..599ac968b0 100644 --- a/target/i386/tcg/int_helper.c +++ b/target/i386/tcg/int_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "qemu/host-utils.h" diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index 5769db5ace..24a0eaa3d5 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c index 824b9a5a26..2c9bd007ad 100644 --- a/target/i386/tcg/sysemu/seg_helper.c +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 6d39611eb6..2b6f450af9 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 1430e318d7..ad8843f5aa 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -7402,6 +7402,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0: /* sldt */ if (!PE(s) || VM86(s)) goto illegal_op; + if (s->flags & HF_UMIP_MASK && !check_cpl0(s)) { + break; + } gen_svm_check_intercept(s, SVM_EXIT_LDTR_READ); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, ldt.selector)); @@ -7421,6 +7424,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 1: /* str */ if (!PE(s) || VM86(s)) goto illegal_op; + if (s->flags & HF_UMIP_MASK && !check_cpl0(s)) { + break; + } gen_svm_check_intercept(s, SVM_EXIT_TR_READ); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, tr.selector)); @@ -7459,6 +7465,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) modrm = x86_ldub_code(env, s); switch (modrm) { CASE_MODRM_MEM_OP(0): /* sgdt */ + if (s->flags & HF_UMIP_MASK && !check_cpl0(s)) { + break; + } gen_svm_check_intercept(s, SVM_EXIT_GDTR_READ); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, @@ -7515,6 +7524,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; CASE_MODRM_MEM_OP(1): /* sidt */ + if (s->flags & HF_UMIP_MASK && !check_cpl0(s)) { + break; + } gen_svm_check_intercept(s, SVM_EXIT_IDTR_READ); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.limit)); @@ -7690,6 +7702,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; CASE_MODRM_OP(4): /* smsw */ + if (s->flags & HF_UMIP_MASK && !check_cpl0(s)) { + break; + } gen_svm_check_intercept(s, SVM_EXIT_READ_CR0); tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, cr[0])); /* diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index acbd473515..8decc61240 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index b9c888b87e..aed200dcff 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -22,6 +22,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qapi/error.h" #include "cpu.h" #include "qemu/module.h" diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index cc40f275ea..75651979a9 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 58d633584d..5b745d0928 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" diff --git a/target/mips/tcg/exception.c b/target/mips/tcg/exception.c index 7b3026b105..0b21e0872b 100644 --- a/target/mips/tcg/exception.c +++ b/target/mips/tcg/exception.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "internal.h" #include "exec/helper-proto.h" diff --git a/target/mips/tcg/sysemu/special_helper.c b/target/mips/tcg/sysemu/special_helper.c index 2a2afb49e8..f4f8fe8afc 100644 --- a/target/mips/tcg/sysemu/special_helper.c +++ b/target/mips/tcg/sysemu/special_helper.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h index ae01515efe..9997fe2f3c 100644 --- a/target/mips/tcg/translate.h +++ b/target/mips/tcg/translate.h @@ -8,6 +8,7 @@ #ifndef TARGET_MIPS_TRANSLATE_H #define TARGET_MIPS_TRANSLATE_H +#include "qemu/log.h" #include "exec/translator.h" #define MIPS_DEBUG_DISAS 0 diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index 19223e3f25..e5724f5371 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "exec/gdbstub.h" diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index e561ef245b..d7e1320998 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "exec/gdbstub.h" diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 555c6b9245..5b01d409b3 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1311,6 +1311,8 @@ PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc); #ifndef CONFIG_USER_ONLY struct PPCVirtualHypervisorClass { InterfaceClass parent; + bool (*cpu_in_nested)(PowerPCCPU *cpu); + void (*deliver_hv_excp)(PowerPCCPU *cpu, int excp); void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); hwaddr (*hpt_mask)(PPCVirtualHypervisor *vhyp); const ppc_hash_pte64_t *(*map_hptes)(PPCVirtualHypervisor *vhyp, @@ -1320,7 +1322,8 @@ struct PPCVirtualHypervisorClass { hwaddr ptex, int n); void (*hpte_set_c)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1); void (*hpte_set_r)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1); - void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry); + bool (*get_pate)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu, + target_ulong lpid, ppc_v3_pate_t *entry); target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp); void (*cpu_exec_enter)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); void (*cpu_exec_exit)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); @@ -1329,6 +1332,11 @@ struct PPCVirtualHypervisorClass { #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor" DECLARE_OBJ_CHECKERS(PPCVirtualHypervisor, PPCVirtualHypervisorClass, PPC_VIRTUAL_HYPERVISOR, TYPE_PPC_VIRTUAL_HYPERVISOR) + +static inline bool vhyp_cpu_in_nested(PowerPCCPU *cpu) +{ + return PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp)->cpu_in_nested(cpu); +} #endif /* CONFIG_USER_ONLY */ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags); @@ -2724,4 +2732,43 @@ void dump_mmu(CPUPPCState *env); void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len); void ppc_store_vscr(CPUPPCState *env, uint32_t vscr); uint32_t ppc_get_vscr(CPUPPCState *env); + +/*****************************************************************************/ +/* Power management enable checks */ +static inline int check_pow_none(CPUPPCState *env) +{ + return 0; +} + +static inline int check_pow_nocheck(CPUPPCState *env) +{ + return 1; +} + +/*****************************************************************************/ +/* PowerPC implementations definitions */ + +#define POWERPC_FAMILY(_name) \ + static void \ + glue(glue(ppc_, _name), _cpu_family_class_init)(ObjectClass *, void *); \ + \ + static const TypeInfo \ + glue(glue(ppc_, _name), _cpu_family_type_info) = { \ + .name = stringify(_name) "-family-" TYPE_POWERPC_CPU, \ + .parent = TYPE_POWERPC_CPU, \ + .abstract = true, \ + .class_init = glue(glue(ppc_, _name), _cpu_family_class_init), \ + }; \ + \ + static void glue(glue(ppc_, _name), _cpu_family_register_types)(void) \ + { \ + type_register_static( \ + &glue(glue(ppc_, _name), _cpu_family_type_info)); \ + } \ + \ + type_init(glue(glue(ppc_, _name), _cpu_family_register_types)) \ + \ + static void glue(glue(ppc_, _name), _cpu_family_class_init) + + #endif /* PPC_CPU_H */ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index d97f718354..61d36b11a0 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -44,7 +44,7 @@ #include "helper_regs.h" #include "internal.h" -#include "spr_tcg.h" +#include "spr_common.h" #include "power8-pmu.h" /* #define PPC_DEBUG_SPR */ @@ -57,391 +57,7 @@ static inline void vscr_init(CPUPPCState *env, uint32_t val) ppc_store_vscr(env, val); } -/** - * _spr_register - * - * Register an SPR with all the callbacks required for tcg, - * and the ID number for KVM. - * - * The reason for the conditional compilation is that the tcg functions - * may be compiled out, and the system kvm header may not be available - * for supplying the ID numbers. This is ugly, but the best we can do. - */ - -#ifdef CONFIG_TCG -# define USR_ARG(X) X, -# ifdef CONFIG_USER_ONLY -# define SYS_ARG(X) -# else -# define SYS_ARG(X) X, -# endif -#else -# define USR_ARG(X) -# define SYS_ARG(X) -#endif -#ifdef CONFIG_KVM -# define KVM_ARG(X) X, -#else -# define KVM_ARG(X) -#endif - -typedef void spr_callback(DisasContext *, int, int); - -static void _spr_register(CPUPPCState *env, int num, const char *name, - USR_ARG(spr_callback *uea_read) - USR_ARG(spr_callback *uea_write) - SYS_ARG(spr_callback *oea_read) - SYS_ARG(spr_callback *oea_write) - SYS_ARG(spr_callback *hea_read) - SYS_ARG(spr_callback *hea_write) - KVM_ARG(uint64_t one_reg_id) - target_ulong initial_value) -{ - ppc_spr_t *spr = &env->spr_cb[num]; - - /* No SPR should be registered twice. */ - assert(spr->name == NULL); - assert(name != NULL); - - spr->name = name; - spr->default_value = initial_value; - env->spr[num] = initial_value; - -#ifdef CONFIG_TCG - spr->uea_read = uea_read; - spr->uea_write = uea_write; -# ifndef CONFIG_USER_ONLY - spr->oea_read = oea_read; - spr->oea_write = oea_write; - spr->hea_read = hea_read; - spr->hea_write = hea_write; -# endif -#endif -#ifdef CONFIG_KVM - spr->one_reg_id = one_reg_id; -#endif -} - -/* spr_register_kvm_hv passes all required arguments. */ -#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, \ - one_reg_id, initial_value) \ - _spr_register(env, num, name, \ - USR_ARG(uea_read) USR_ARG(uea_write) \ - SYS_ARG(oea_read) SYS_ARG(oea_write) \ - SYS_ARG(hea_read) SYS_ARG(hea_write) \ - KVM_ARG(one_reg_id) initial_value) - -/* spr_register_kvm duplicates the oea callbacks to the hea callbacks. */ -#define spr_register_kvm(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, ival) \ - spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \ - oea_write, oea_read, oea_write, one_reg_id, ival) - -/* spr_register_hv and spr_register are similar, except there is no kvm id. */ -#define spr_register_hv(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, ival) \ - spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \ - oea_write, hea_read, hea_write, 0, ival) - -#define spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, ival) \ - spr_register_kvm(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, 0, ival) - -/* Generic PowerPC SPRs */ -static void register_generic_sprs(CPUPPCState *env) -{ - /* Integer processing */ - spr_register(env, SPR_XER, "XER", - &spr_read_xer, &spr_write_xer, - &spr_read_xer, &spr_write_xer, - 0x00000000); - /* Branch control */ - spr_register(env, SPR_LR, "LR", - &spr_read_lr, &spr_write_lr, - &spr_read_lr, &spr_write_lr, - 0x00000000); - spr_register(env, SPR_CTR, "CTR", - &spr_read_ctr, &spr_write_ctr, - &spr_read_ctr, &spr_write_ctr, - 0x00000000); - /* Interrupt processing */ - spr_register(env, SPR_SRR0, "SRR0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_SRR1, "SRR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Processor control */ - spr_register(env, SPR_SPRG0, "SPRG0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_SPRG1, "SPRG1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_SPRG2, "SPRG2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_SPRG3, "SPRG3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -} - -/* SPR common to all non-embedded PowerPC, including 601 */ -static void register_ne_601_sprs(CPUPPCState *env) -{ - /* Exception processing */ - spr_register_kvm(env, SPR_DSISR, "DSISR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_DSISR, 0x00000000); - spr_register_kvm(env, SPR_DAR, "DAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_DAR, 0x00000000); - /* Timer */ - spr_register(env, SPR_DECR, "DECR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_decr, &spr_write_decr, - 0x00000000); -} - -/* Storage Description Register 1 */ -static void register_sdr1_sprs(CPUPPCState *env) -{ -#ifndef CONFIG_USER_ONLY - if (env->has_hv_mode) { - /* - * SDR1 is a hypervisor resource on CPUs which have a - * hypervisor mode - */ - spr_register_hv(env, SPR_SDR1, "SDR1", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_sdr1, - 0x00000000); - } else { - spr_register(env, SPR_SDR1, "SDR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_sdr1, - 0x00000000); - } -#endif -} - -/* BATs 0-3 */ -static void register_low_BATs(CPUPPCState *env) -{ -#if !defined(CONFIG_USER_ONLY) - spr_register(env, SPR_IBAT0U, "IBAT0U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatu, - 0x00000000); - spr_register(env, SPR_IBAT0L, "IBAT0L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatl, - 0x00000000); - spr_register(env, SPR_IBAT1U, "IBAT1U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatu, - 0x00000000); - spr_register(env, SPR_IBAT1L, "IBAT1L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatl, - 0x00000000); - spr_register(env, SPR_IBAT2U, "IBAT2U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatu, - 0x00000000); - spr_register(env, SPR_IBAT2L, "IBAT2L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatl, - 0x00000000); - spr_register(env, SPR_IBAT3U, "IBAT3U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatu, - 0x00000000); - spr_register(env, SPR_IBAT3L, "IBAT3L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat, &spr_write_ibatl, - 0x00000000); - spr_register(env, SPR_DBAT0U, "DBAT0U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatu, - 0x00000000); - spr_register(env, SPR_DBAT0L, "DBAT0L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatl, - 0x00000000); - spr_register(env, SPR_DBAT1U, "DBAT1U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatu, - 0x00000000); - spr_register(env, SPR_DBAT1L, "DBAT1L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatl, - 0x00000000); - spr_register(env, SPR_DBAT2U, "DBAT2U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatu, - 0x00000000); - spr_register(env, SPR_DBAT2L, "DBAT2L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatl, - 0x00000000); - spr_register(env, SPR_DBAT3U, "DBAT3U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatu, - 0x00000000); - spr_register(env, SPR_DBAT3L, "DBAT3L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat, &spr_write_dbatl, - 0x00000000); - env->nb_BATs += 4; -#endif -} - -/* BATs 4-7 */ -static void register_high_BATs(CPUPPCState *env) -{ -#if !defined(CONFIG_USER_ONLY) - spr_register(env, SPR_IBAT4U, "IBAT4U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatu_h, - 0x00000000); - spr_register(env, SPR_IBAT4L, "IBAT4L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatl_h, - 0x00000000); - spr_register(env, SPR_IBAT5U, "IBAT5U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatu_h, - 0x00000000); - spr_register(env, SPR_IBAT5L, "IBAT5L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatl_h, - 0x00000000); - spr_register(env, SPR_IBAT6U, "IBAT6U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatu_h, - 0x00000000); - spr_register(env, SPR_IBAT6L, "IBAT6L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatl_h, - 0x00000000); - spr_register(env, SPR_IBAT7U, "IBAT7U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatu_h, - 0x00000000); - spr_register(env, SPR_IBAT7L, "IBAT7L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_ibat_h, &spr_write_ibatl_h, - 0x00000000); - spr_register(env, SPR_DBAT4U, "DBAT4U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatu_h, - 0x00000000); - spr_register(env, SPR_DBAT4L, "DBAT4L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatl_h, - 0x00000000); - spr_register(env, SPR_DBAT5U, "DBAT5U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatu_h, - 0x00000000); - spr_register(env, SPR_DBAT5L, "DBAT5L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatl_h, - 0x00000000); - spr_register(env, SPR_DBAT6U, "DBAT6U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatu_h, - 0x00000000); - spr_register(env, SPR_DBAT6L, "DBAT6L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatl_h, - 0x00000000); - spr_register(env, SPR_DBAT7U, "DBAT7U", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatu_h, - 0x00000000); - spr_register(env, SPR_DBAT7L, "DBAT7L", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_dbat_h, &spr_write_dbatl_h, - 0x00000000); - env->nb_BATs += 4; -#endif -} - -/* Generic PowerPC time base */ -static void register_tbl(CPUPPCState *env) -{ - spr_register(env, SPR_VTBL, "TBL", - &spr_read_tbl, SPR_NOACCESS, - &spr_read_tbl, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_TBL, "TBL", - &spr_read_tbl, SPR_NOACCESS, - &spr_read_tbl, &spr_write_tbl, - 0x00000000); - spr_register(env, SPR_VTBU, "TBU", - &spr_read_tbu, SPR_NOACCESS, - &spr_read_tbu, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_TBU, "TBU", - &spr_read_tbu, SPR_NOACCESS, - &spr_read_tbu, &spr_write_tbu, - 0x00000000); -} - -/* Softare table search registers */ -static void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) -{ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = nb_tlbs; - env->nb_ways = nb_ways; - env->id_tlbs = 1; - env->tlb_type = TLB_6XX; - spr_register(env, SPR_DMISS, "DMISS", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_DCMP, "DCMP", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_HASH1, "HASH1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_HASH2, "HASH2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_IMISS, "IMISS", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_ICMP, "ICMP", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_RPA, "RPA", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -#endif -} - -/* SPR common to MPC755 and G2 */ -static void register_G2_755_sprs(CPUPPCState *env) +static void register_745_sprs(CPUPPCState *env) { /* SGPRs */ spr_register(env, SPR_SPRG4, "SPRG4", @@ -460,105 +76,142 @@ static void register_G2_755_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + + /* Hardware implementation registers */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +static void register_755_sprs(CPUPPCState *env) +{ + /* L2 cache control */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, spr_access_nop, + 0x00000000); + + spr_register(env, SPR_L2PMCR, "L2PMCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } /* SPR common to all 7xx PowerPC implementations */ static void register_7xx_sprs(CPUPPCState *env) { /* Breakpoints */ - /* XXX : not implemented */ spr_register_kvm(env, SPR_DABR, "DABR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, KVM_REG_PPC_DABR, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Cache management */ - /* XXX : not implemented */ spr_register(env, SPR_ICTC, "ICTC", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Performance monitors */ - /* XXX : not implemented */ spr_register(env, SPR_7XX_MMCR0, "MMCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_MMCR1, "MMCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC1, "PMC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC2, "PMC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC3, "PMC3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC4, "PMC4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_SIAR, "SIAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UMMCR0, "UMMCR0", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UMMCR1, "UMMCR1", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC1, "UPMC1", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC2, "UPMC2", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC3, "UPMC3", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC4, "UPMC4", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_USIAR, "USIAR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* External access control */ - /* XXX : not implemented */ spr_register(env, SPR_EAR, "EAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + + /* Hardware implementation registers */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } #ifdef TARGET_PPC64 @@ -606,26 +259,6 @@ static void register_iamr_sprs(CPUPPCState *env) } #endif /* TARGET_PPC64 */ -static void register_thrm_sprs(CPUPPCState *env) -{ - /* Thermal management */ - /* XXX : not implemented */ - spr_register(env, SPR_THRM1, "THRM1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_thrm, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_THRM2, "THRM2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_thrm, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_THRM3, "THRM3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_thrm, &spr_write_generic, - 0x00000000); -} - /* SPR specific to PowerPC 604 implementation */ static void register_604_sprs(CPUPPCState *env) { @@ -635,66 +268,133 @@ static void register_604_sprs(CPUPPCState *env) &spr_read_generic, &spr_write_pir, 0x00000000); /* Breakpoints */ - /* XXX : not implemented */ spr_register(env, SPR_IABR, "IABR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register_kvm(env, SPR_DABR, "DABR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, KVM_REG_PPC_DABR, 0x00000000); /* Performance counters */ - /* XXX : not implemented */ spr_register(env, SPR_7XX_MMCR0, "MMCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC1, "PMC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC2, "PMC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_SIAR, "SIAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_SDA, "SDA", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* External access control */ - /* XXX : not implemented */ spr_register(env, SPR_EAR, "EAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + + /* Hardware implementation registers */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +static void register_604e_sprs(CPUPPCState *env) +{ + spr_register(env, SPR_7XX_MMCR1, "MMCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_PMC3, "PMC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_PMC4, "PMC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } /* SPR specific to PowerPC 603 implementation */ static void register_603_sprs(CPUPPCState *env) { /* External access control */ - /* XXX : not implemented */ spr_register(env, SPR_EAR, "EAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Breakpoints */ - /* XXX : not implemented */ spr_register(env, SPR_IABR, "IABR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +static void register_e300_sprs(CPUPPCState *env) +{ + /* hardware implementation registers */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Breakpoints */ + spr_register(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_DABR2, "DABR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_IABR2, "IABR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_IBCR, "IBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_DBCR, "DBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } /* SPR specific to PowerPC G2 implementation */ @@ -702,7 +402,6 @@ static void register_G2_sprs(CPUPPCState *env) { /* Memory base address */ /* MBAR */ - /* XXX : not implemented */ spr_register(env, SPR_MBAR, "MBAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -717,72 +416,200 @@ static void register_G2_sprs(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Breakpoints */ - /* XXX : not implemented */ spr_register(env, SPR_DABR, "DABR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_DABR2, "DABR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_IABR2, "IABR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_IBCR, "IBCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_DBCR, "DBCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + + /* External access control */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation register */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + /* SGPRs */ + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } static void register_74xx_sprs(CPUPPCState *env) { + /* Breakpoints */ + spr_register_kvm(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DABR, 0x00000000); + + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Cache management */ + spr_register(env, SPR_ICTC, "ICTC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Performance monitors */ + spr_register(env, SPR_7XX_MMCR0, "MMCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_MMCR1, "MMCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_PMC1, "PMC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_PMC2, "PMC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_PMC3, "PMC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_PMC4, "PMC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_7XX_SIAR, "SIAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + + spr_register(env, SPR_7XX_UMMCR0, "UMMCR0", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + + spr_register(env, SPR_7XX_UMMCR1, "UMMCR1", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + + spr_register(env, SPR_7XX_UPMC1, "UPMC1", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + + spr_register(env, SPR_7XX_UPMC2, "UPMC2", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + + spr_register(env, SPR_7XX_UPMC3, "UPMC3", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + + spr_register(env, SPR_7XX_UPMC4, "UPMC4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + + spr_register(env, SPR_7XX_USIAR, "USIAR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* External access control */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Processor identification */ spr_register(env, SPR_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_pir, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_74XX_MMCR2, "MMCR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_74XX_UMMCR2, "UMMCR2", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX: not implemented */ + spr_register(env, SPR_BAMR, "BAMR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MSSCR0, "MSSCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Hardware implementation registers */ - /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -792,7 +619,7 @@ static void register_74xx_sprs(CPUPPCState *env) &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, @@ -802,53 +629,22 @@ static void register_74xx_sprs(CPUPPCState *env) static void register_l3_ctrl(CPUPPCState *env) { /* L3CR */ - /* XXX : not implemented */ spr_register(env, SPR_L3CR, "L3CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR0 */ - /* XXX : not implemented */ spr_register(env, SPR_L3ITCR0, "L3ITCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3PM */ - /* XXX : not implemented */ spr_register(env, SPR_L3PM, "L3PM", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); } -static void register_usprg3_sprs(CPUPPCState *env) -{ - spr_register(env, SPR_USPRG3, "USPRG3", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); -} - -static void register_usprgh_sprs(CPUPPCState *env) -{ - spr_register(env, SPR_USPRG4, "USPRG4", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_USPRG5, "USPRG5", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_USPRG6, "USPRG6", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_USPRG7, "USPRG7", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); -} - /* PowerPC BookE SPR */ static void register_BookE_sprs(CPUPPCState *env, uint64_t ivor_mask) { @@ -901,37 +697,36 @@ static void register_BookE_sprs(CPUPPCState *env, uint64_t ivor_mask) &spr_read_generic, &spr_write_generic, 0x00000000); /* Debug */ - /* XXX : not implemented */ spr_register(env, SPR_BOOKE_IAC1, "IAC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC2, "IAC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DAC1, "DAC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DAC2, "DAC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR0, "DBCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_40x_dbcr0, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR1, "DBCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR2, "DBCR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -944,7 +739,7 @@ static void register_BookE_sprs(CPUPPCState *env, uint64_t ivor_mask) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBSR, "DBSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, @@ -1053,7 +848,6 @@ static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask, int i; /* TLB assist registers */ - /* XXX : not implemented */ for (i = 0; i < 8; i++) { if (mas_mask & (1 << i)) { spr_register(env, mas_sprn[i], mas_names[i], @@ -1065,14 +859,12 @@ static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask, } } if (env->nb_pids > 1) { - /* XXX : not implemented */ spr_register(env, SPR_BOOKE_PID1, "PID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_booke_pid, 0x00000000); } if (env->nb_pids > 2) { - /* XXX : not implemented */ spr_register(env, SPR_BOOKE_PID2, "PID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_booke_pid, @@ -1088,7 +880,6 @@ static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask, &spr_read_generic, &spr_write_epsc, 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_MMUCFG, "MMUCFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -1123,131 +914,127 @@ static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask, break; } #endif - - register_usprgh_sprs(env); } /* SPR specific to PowerPC 440 implementation */ static void register_440_sprs(CPUPPCState *env) { /* Cache control */ - /* XXX : not implemented */ spr_register(env, SPR_440_DNV0, "DNV0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DNV1, "DNV1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DNV2, "DNV2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DNV3, "DNV3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DTV0, "DTV0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DTV1, "DTV1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DTV2, "DTV2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DTV3, "DTV3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DVLIM, "DVLIM", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_INV0, "INV0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_INV1, "INV1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_INV2, "INV2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_INV3, "INV3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_ITV0, "ITV0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_ITV1, "ITV1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_ITV2, "ITV2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_ITV3, "ITV3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_IVLIM, "IVLIM", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Cache debug */ - /* XXX : not implemented */ spr_register(env, SPR_BOOKE_DCDBTRH, "DCDBTRH", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DCDBTRL, "DCDBTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_ICDBTRH, "ICDBTRH", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_ICDBTRL, "ICDBTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_DBDR, "DBDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1266,6 +1053,32 @@ static void register_440_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } /* SPR shared between PowerPC 40x implementations */ @@ -1336,23 +1149,22 @@ static void register_405_sprs(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00700000); /* Debug interface */ - /* XXX : not implemented */ spr_register(env, SPR_40x_DBCR0, "DBCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_40x_dbcr0, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_405_DBCR1, "DBCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_40x_DBSR, "DBSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, /* Last reset was system reset */ 0x00000300); - /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC1, "DAC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1361,17 +1173,17 @@ static void register_405_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_405_DVC1, "DVC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_405_DVC2, "DVC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC1, "IAC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1380,18 +1192,17 @@ static void register_405_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_405_IAC3, "IAC3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_405_IAC4, "IAC4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Storage control */ - /* XXX: TODO: not implemented */ spr_register(env, SPR_405_SLER, "SLER", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_40x_sler, @@ -1400,7 +1211,7 @@ static void register_405_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_405_SU0R, "SU0R", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1426,7 +1237,18 @@ static void register_405_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, spr_read_generic, &spr_write_generic, 0x00000000); - register_usprgh_sprs(env); + + /* Bus access control */ + /* not emulated, as QEMU never does speculative access */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* not emulated, as QEMU do not emulate caches */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } @@ -1446,102 +1268,102 @@ static void register_5xx_8xx_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_decr, &spr_write_decr, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_EIE, "EIE", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_EID, "EID", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_NRI, "NRI", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPA, "CMPA", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPB, "CMPB", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPC, "CMPC", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPD, "CMPD", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_ECR, "ECR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_DER, "DER", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_COUNTA, "COUNTA", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_COUNTB, "COUNTB", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPE, "CMPE", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPF, "CMPF", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPG, "CMPG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPH, "CMPH", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_LCTRL1, "LCTRL1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_LCTRL2, "LCTRL2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_BAR, "BAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_DPDR, "DPDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_IMMR, "IMMR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1550,107 +1372,106 @@ static void register_5xx_8xx_sprs(CPUPPCState *env) static void register_5xx_sprs(CPUPPCState *env) { - /* XXX : not implemented */ spr_register(env, SPR_RCPU_MI_GRA, "MI_GRA", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_GRA, "L2U_GRA", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RPCU_BBCMCR, "L2U_BBCMCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_MCR, "L2U_MCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA0, "MI_RBA0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA1, "MI_RBA1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA2, "MI_RBA2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA3, "MI_RBA3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA0, "L2U_RBA0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA1, "L2U_RBA1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA2, "L2U_RBA2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA3, "L2U_RBA3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA0, "MI_RA0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA1, "MI_RA1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA2, "MI_RA2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA3, "MI_RA3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA0, "L2U_RA0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA1, "L2U_RA1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA2, "L2U_RA2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA3, "L2U_RA3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_RCPU_FPECR, "FPECR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1659,127 +1480,127 @@ static void register_5xx_sprs(CPUPPCState *env) static void register_8xx_sprs(CPUPPCState *env) { - /* XXX : not implemented */ + spr_register(env, SPR_MPC_IC_CST, "IC_CST", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_IC_ADR, "IC_ADR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_IC_DAT, "IC_DAT", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_DC_CST, "DC_CST", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_DC_ADR, "DC_ADR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_DC_DAT, "DC_DAT", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_CTR, "MI_CTR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_AP, "MI_AP", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_EPN, "MI_EPN", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_TWC, "MI_TWC", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_RPN, "MI_RPN", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_DBCAM, "MI_DBCAM", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_DBRAM0, "MI_DBRAM0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_DBRAM1, "MI_DBRAM1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_CTR, "MD_CTR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_CASID, "MD_CASID", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_AP, "MD_AP", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_EPN, "MD_EPN", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_TWB, "MD_TWB", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_TWC, "MD_TWC", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_RPN, "MD_RPN", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_TW, "MD_TW", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_DBCAM, "MD_DBCAM", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_DBRAM0, "MD_DBRAM0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_DBRAM1, "MD_DBRAM1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2259,18 +2080,6 @@ static void init_excp_POWER10(CPUPPCState *env) #endif -/*****************************************************************************/ -/* Power management enable checks */ -static int check_pow_none(CPUPPCState *env) -{ - return 0; -} - -static int check_pow_nocheck(CPUPPCState *env) -{ - return 1; -} - static int check_pow_hid0(CPUPPCState *env) { if (env->spr[SPR_HID0] & 0x00E00000) { @@ -2289,48 +2098,12 @@ static int check_pow_hid0_74xx(CPUPPCState *env) return 0; } -/*****************************************************************************/ -/* PowerPC implementations definitions */ - -#define POWERPC_FAMILY(_name) \ - static void \ - glue(glue(ppc_, _name), _cpu_family_class_init)(ObjectClass *, void *); \ - \ - static const TypeInfo \ - glue(glue(ppc_, _name), _cpu_family_type_info) = { \ - .name = stringify(_name) "-family-" TYPE_POWERPC_CPU, \ - .parent = TYPE_POWERPC_CPU, \ - .abstract = true, \ - .class_init = glue(glue(ppc_, _name), _cpu_family_class_init), \ - }; \ - \ - static void glue(glue(ppc_, _name), _cpu_family_register_types)(void) \ - { \ - type_register_static( \ - &glue(glue(ppc_, _name), _cpu_family_type_info)); \ - } \ - \ - type_init(glue(glue(ppc_, _name), _cpu_family_register_types)) \ - \ - static void glue(glue(ppc_, _name), _cpu_family_class_init) - static void init_proc_405(CPUPPCState *env) { - /* Time base */ - register_tbl(env); register_40x_sprs(env); register_405_sprs(env); - /* Bus access control */ - /* not emulated, as QEMU never does speculative access */ - spr_register(env, SPR_40x_SGR, "SGR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0xFFFFFFFF); - /* not emulated, as QEMU do not emulate caches */ - spr_register(env, SPR_40x_DCWR, "DCWR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + register_usprgh_sprs(env); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; @@ -2383,37 +2156,10 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) static void init_proc_440EP(CPUPPCState *env) { - /* Time base */ - register_tbl(env); register_BookE_sprs(env, 0x000000000000FFFFULL); register_440_sprs(env); register_usprgh_sprs(env); - /* Processor identification */ - spr_register(env, SPR_BOOKE_PIR, "PIR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_pir, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC3, "IAC3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC4, "IAC4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC1, "DVC1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC2, "DVC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2426,7 +2172,7 @@ static void init_proc_440EP(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_CCR1, "CCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2525,36 +2271,10 @@ POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data) static void init_proc_440GP(CPUPPCState *env) { - /* Time base */ - register_tbl(env); register_BookE_sprs(env, 0x000000000000FFFFULL); register_440_sprs(env); register_usprgh_sprs(env); - /* Processor identification */ - spr_register(env, SPR_BOOKE_PIR, "PIR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_pir, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC3, "IAC3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC4, "IAC4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC1, "DVC1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC2, "DVC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; @@ -2608,37 +2328,10 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) static void init_proc_440x5(CPUPPCState *env) { - /* Time base */ - register_tbl(env); register_BookE_sprs(env, 0x000000000000FFFFULL); register_440_sprs(env); register_usprgh_sprs(env); - /* Processor identification */ - spr_register(env, SPR_BOOKE_PIR, "PIR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_pir, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC3, "IAC3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC4, "IAC4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC1, "DVC1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC2, "DVC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2651,7 +2344,7 @@ static void init_proc_440x5(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_440_CCR1, "CCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2747,8 +2440,6 @@ POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data) static void init_proc_MPC5xx(CPUPPCState *env) { - /* Time base */ - register_tbl(env); register_5xx_8xx_sprs(env); register_5xx_sprs(env); init_excp_MPC5xx(env); @@ -2791,8 +2482,6 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) static void init_proc_MPC8xx(CPUPPCState *env) { - /* Time base */ - register_tbl(env); register_5xx_8xx_sprs(env); register_8xx_sprs(env); init_excp_MPC8xx(env); @@ -2836,34 +2525,10 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) static void init_proc_G2(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_G2_755_sprs(env); register_G2_sprs(env); - /* Time base */ - register_tbl(env); - /* External access control */ - /* XXX : not implemented */ - spr_register(env, SPR_EAR, "EAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Hardware implementation register */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ register_low_BATs(env); register_high_BATs(env); @@ -2913,55 +2578,13 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -static void init_proc_G2LE(CPUPPCState *env) -{ - register_ne_601_sprs(env); - register_sdr1_sprs(env); - register_G2_755_sprs(env); - register_G2_sprs(env); - /* Time base */ - register_tbl(env); - /* External access control */ - /* XXX : not implemented */ - spr_register(env, SPR_EAR, "EAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Hardware implementation register */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - - /* Memory management */ - register_low_BATs(env); - register_high_BATs(env); - register_6xx_7xx_soft_tlb(env, 64, 2); - init_excp_G2(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env_archcpu(env)); -} - POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); dc->desc = "PowerPC G2LE"; - pcc->init_proc = init_proc_G2LE; + pcc->init_proc = init_proc_G2; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | @@ -2997,87 +2620,86 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) static void init_proc_e200(CPUPPCState *env) { - /* Time base */ - register_tbl(env); register_BookE_sprs(env, 0x000000070000FFFFULL); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR", &spr_read_spefscr, &spr_write_spefscr, &spr_read_spefscr, &spr_write_spefscr, 0x00000000); /* Memory management */ register_BookE206_sprs(env, 0x0000005D, NULL, 0); - /* XXX : not implemented */ + register_usprgh_sprs(env); + spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_ALTCTXCR, "ALTCTXCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_BUCSR, "BUCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_CTXCR, "CTXCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_DBCNT, "DBCNT", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_DBCR3, "DBCR3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0", &spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1FINV0, "L1FINV0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MMUCSR0, "MMUCSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -3150,106 +2772,6 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -static void init_proc_e300(CPUPPCState *env) -{ - register_ne_601_sprs(env); - register_sdr1_sprs(env); - register_603_sprs(env); - /* Time base */ - register_tbl(env); - /* hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Breakpoints */ - /* XXX : not implemented */ - spr_register(env, SPR_DABR, "DABR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_DABR2, "DABR2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_IABR2, "IABR2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_IBCR, "IBCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_DBCR, "DBCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ - register_low_BATs(env); - register_high_BATs(env); - register_6xx_7xx_soft_tlb(env, 64, 2); - init_excp_603(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env_archcpu(env)); -} - -POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - - dc->desc = "e300 core"; - pcc->init_proc = init_proc_e300; - pcc->check_pow = check_pow_hid0; - pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | - PPC_FLOAT_STFIWX | - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | - PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | - PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = (1ull << MSR_POW) | - (1ull << MSR_TGPR) | - (1ull << MSR_ILE) | - (1ull << MSR_EE) | - (1ull << MSR_PR) | - (1ull << MSR_FP) | - (1ull << MSR_ME) | - (1ull << MSR_FE0) | - (1ull << MSR_SE) | - (1ull << MSR_DE) | - (1ull << MSR_FE1) | - (1ull << MSR_AL) | - (1ull << MSR_EP) | - (1ull << MSR_IR) | - (1ull << MSR_DR) | - (1ull << MSR_RI) | - (1ull << MSR_LE); - pcc->mmu_model = POWERPC_MMU_SOFT_6xx; - pcc->excp_model = POWERPC_EXCP_6xx; - pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_603; - pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; -} - enum fsl_e500_version { fsl_e500v1, fsl_e500v2, @@ -3272,8 +2794,6 @@ static void init_proc_e500(CPUPPCState *env, int version) int i; #endif - /* Time base */ - register_tbl(env); /* * XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't * complain when accessing them. @@ -3294,13 +2814,18 @@ static void init_proc_e500(CPUPPCState *env, int version) break; } register_BookE_sprs(env, ivor_mask); - register_usprg3_sprs(env); + + spr_register(env, SPR_USPRG3, "USPRG3", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Processor identification */ spr_register(env, SPR_BOOKE_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_pir, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR", &spr_read_spefscr, &spr_write_spefscr, &spr_read_spefscr, &spr_write_spefscr, @@ -3360,47 +2885,48 @@ static void init_proc_e500(CPUPPCState *env, int version) env->spr[SPR_PVR]); } register_BookE206_sprs(env, 0x000000DF, tlbncfg, mmucfg); - /* XXX : not implemented */ + register_usprgh_sprs(env); + spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_BBEAR, "BBEAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_BBTAR, "BBTAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_MCAR, "MCAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_NPIDR, "NPIDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_BUCSR, "BUCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0", &spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -3714,22 +3240,10 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data) /* Non-embedded PowerPC */ static void init_proc_603(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_603_sprs(env); - /* Time base */ - register_tbl(env); - /* hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ register_low_BATs(env); register_6xx_7xx_soft_tlb(env, 64, 2); @@ -3818,19 +3332,58 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } +static void init_proc_e300(CPUPPCState *env) +{ + init_proc_603(env); + register_e300_sprs(env); +} + +POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "e300 core"; + pcc->init_proc = init_proc_e300; + pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_TGPR) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_AL) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI) | + (1ull << MSR_LE); + pcc->mmu_model = POWERPC_MMU_SOFT_6xx; + pcc->excp_model = POWERPC_EXCP_6xx; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_603; + pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; +} + static void init_proc_604(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_604_sprs(env); - /* Time base */ - register_tbl(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ register_low_BATs(env); init_excp_604(env); @@ -3881,44 +3434,8 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) static void init_proc_604E(CPUPPCState *env) { - register_ne_601_sprs(env); - register_sdr1_sprs(env); - register_604_sprs(env); - /* XXX : not implemented */ - spr_register(env, SPR_7XX_MMCR1, "MMCR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_7XX_PMC3, "PMC3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_7XX_PMC4, "PMC4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Time base */ - register_tbl(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ - register_low_BATs(env); - init_excp_604(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env_archcpu(env)); + init_proc_604(env); + register_604e_sprs(env); } POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) @@ -3962,24 +3479,12 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) static void init_proc_740(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_7xx_sprs(env); - /* Time base */ - register_tbl(env); /* Thermal management */ register_thrm_sprs(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ register_low_BATs(env); init_excp_7x0(env); @@ -4030,29 +3535,17 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) static void init_proc_750(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_7xx_sprs(env); - /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); - /* Time base */ - register_tbl(env); /* Thermal management */ register_thrm_sprs(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ register_low_BATs(env); /* @@ -4107,16 +3600,14 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) static void init_proc_750cl(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_7xx_sprs(env); - /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); - /* Time base */ - register_tbl(env); /* Thermal management */ /* Those registers are fake on 750CL */ spr_register(env, SPR_THRM1, "THRM1", @@ -4131,7 +3622,7 @@ static void init_proc_750cl(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX: not implemented */ + spr_register(env, SPR_750_TDCL, "TDCL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4141,7 +3632,6 @@ static void init_proc_750cl(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* DMA */ - /* XXX : not implemented */ spr_register(env, SPR_750_WPAR, "WPAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4155,63 +3645,51 @@ static void init_proc_750cl(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_750CL_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750CL_HID4, "HID4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Quantization registers */ - /* XXX : not implemented */ spr_register(env, SPR_750_GQR0, "GQR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750_GQR1, "GQR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750_GQR2, "GQR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750_GQR3, "GQR3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750_GQR4, "GQR4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750_GQR5, "GQR5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750_GQR6, "GQR6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_750_GQR7, "GQR7", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4307,34 +3785,22 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) static void init_proc_750cx(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_7xx_sprs(env); - /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); - /* Time base */ - register_tbl(env); /* Thermal management */ register_thrm_sprs(env); - /* This register is not implemented but is present for compatibility */ + spr_register(env, SPR_SDA, "SDA", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ register_low_BATs(env); /* PowerPC 750cx has 8 DBATs and 8 IBATs */ @@ -4387,35 +3853,22 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) static void init_proc_750fx(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_7xx_sprs(env); - /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); - /* Time base */ - register_tbl(env); /* Thermal management */ register_thrm_sprs(env); - /* XXX : not implemented */ + spr_register(env, SPR_750_THRM4, "THRM4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_750FX_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4472,35 +3925,22 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) static void init_proc_750gx(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_7xx_sprs(env); - /* XXX : not implemented (XXX: different from 750fx) */ + spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); - /* Time base */ - register_tbl(env); /* Thermal management */ register_thrm_sprs(env); - /* XXX : not implemented */ + spr_register(env, SPR_750_THRM4, "THRM4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Hardware implementation registers */ - /* XXX : not implemented (XXX: different from 750fx) */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented (XXX: different from 750fx) */ spr_register(env, SPR_750FX_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4557,30 +3997,13 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) static void init_proc_745(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); register_7xx_sprs(env); - register_G2_755_sprs(env); - /* Time base */ - register_tbl(env); + register_745_sprs(env); /* Thermal management */ register_thrm_sprs(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + /* Memory management */ register_low_BATs(env); register_high_BATs(env); @@ -4633,50 +4056,8 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data) static void init_proc_755(CPUPPCState *env) { - register_ne_601_sprs(env); - register_sdr1_sprs(env); - register_7xx_sprs(env); - register_G2_755_sprs(env); - /* Time base */ - register_tbl(env); - /* L2 cache control */ - /* XXX : not implemented */ - spr_register(env, SPR_L2CR, "L2CR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, spr_access_nop, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_L2PMCR, "L2PMCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Thermal management */ - register_thrm_sprs(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ - register_low_BATs(env); - register_high_BATs(env); - register_6xx_7xx_soft_tlb(env, 64, 2); - init_excp_7x5(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env_archcpu(env)); + init_proc_745(env); + register_755_sprs(env); } POWERPC_FAMILY(755)(ObjectClass *oc, void *data) @@ -4720,21 +4101,16 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data) static void init_proc_7400(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); - /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX: this seems not implemented on all revisions. */ - /* XXX : not implemented */ + spr_register(env, SPR_MSSCR1, "MSSCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4797,15 +4173,11 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) static void init_proc_7410(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); - /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -4813,13 +4185,13 @@ static void init_proc_7410(CPUPPCState *env) /* Thermal management */ register_thrm_sprs(env); /* L2PMCR */ - /* XXX : not implemented */ + spr_register(env, SPR_L2PMCR, "L2PMCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* LDSTDB */ - /* XXX : not implemented */ + spr_register(env, SPR_LDSTDB, "LDSTDB", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4880,54 +4252,46 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) static void init_proc_7440(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); - /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* LDSTCR */ - /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* ICTRL */ - /* XXX : not implemented */ spr_register(env, SPR_ICTRL, "ICTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ - /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* PMC */ - /* XXX : not implemented */ spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -4988,80 +4352,68 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) static void init_proc_7450(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); /* Level 3 cache control */ register_l3_ctrl(env); /* L3ITCR1 */ - /* XXX : not implemented */ spr_register(env, SPR_L3ITCR1, "L3ITCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR2 */ - /* XXX : not implemented */ spr_register(env, SPR_L3ITCR2, "L3ITCR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR3 */ - /* XXX : not implemented */ spr_register(env, SPR_L3ITCR3, "L3ITCR3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3OHCR */ - /* XXX : not implemented */ spr_register(env, SPR_L3OHCR, "L3OHCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* LDSTCR */ - /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* ICTRL */ - /* XXX : not implemented */ spr_register(env, SPR_ICTRL, "ICTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ - /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* PMC */ - /* XXX : not implemented */ spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -5122,49 +4474,41 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) static void init_proc_7445(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); /* LDSTCR */ - /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* ICTRL */ - /* XXX : not implemented */ spr_register(env, SPR_ICTRL, "ICTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ - /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* PMC */ - /* XXX : not implemented */ spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -5259,51 +4603,43 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) static void init_proc_7455(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); /* Level 3 cache control */ register_l3_ctrl(env); /* LDSTCR */ - /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* ICTRL */ - /* XXX : not implemented */ spr_register(env, SPR_ICTRL, "ICTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ - /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* PMC */ - /* XXX : not implemented */ spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -5398,75 +4734,63 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) static void init_proc_7457(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); /* Level 3 cache control */ register_l3_ctrl(env); /* L3ITCR1 */ - /* XXX : not implemented */ spr_register(env, SPR_L3ITCR1, "L3ITCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR2 */ - /* XXX : not implemented */ spr_register(env, SPR_L3ITCR2, "L3ITCR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR3 */ - /* XXX : not implemented */ spr_register(env, SPR_L3ITCR3, "L3ITCR3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3OHCR */ - /* XXX : not implemented */ spr_register(env, SPR_L3OHCR, "L3OHCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* LDSTCR */ - /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* ICTRL */ - /* XXX : not implemented */ spr_register(env, SPR_ICTRL, "ICTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ - /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* PMC */ - /* XXX : not implemented */ spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -5561,50 +4885,46 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) static void init_proc_e600(CPUPPCState *env) { - register_ne_601_sprs(env); + register_non_embedded_sprs(env); register_sdr1_sprs(env); - register_7xx_sprs(env); - /* Time base */ - register_tbl(env); - /* 74xx specific SPR */ register_74xx_sprs(env); vscr_init(env, 0x00010000); - /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_LDSTCR, "LDSTCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_ICTRL, "ICTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -5717,7 +5037,6 @@ static int check_pow_970(CPUPPCState *env) static void register_970_hid_sprs(CPUPPCState *env) { /* Hardware implementation registers */ - /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, @@ -6389,9 +5708,7 @@ static void init_tcg_pmu_power8(CPUPPCState *env) static void init_proc_book3s_common(CPUPPCState *env) { - register_ne_601_sprs(env); - register_tbl(env); - register_usprg3_sprs(env); + register_non_embedded_sprs(env); register_book3s_altivec_sprs(env); register_book3s_pmu_sup_sprs(env); register_book3s_pmu_user_sprs(env); @@ -6401,6 +5718,11 @@ static void init_proc_book3s_common(CPUPPCState *env) * value is the one used by 74xx processors. */ vscr_init(env, 0x00010000); + + spr_register(env, SPR_USPRG3, "USPRG3", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); } static void init_proc_970(CPUPPCState *env) @@ -7353,31 +6675,8 @@ static void init_ppc_proc(PowerPCCPU *cpu) env->tlb_type = TLB_NONE; #endif /* Register SPR common to all PowerPC implementations */ - register_generic_sprs(env); - spr_register(env, SPR_PVR, "PVR", - /* Linux permits userspace to read PVR */ -#if defined(CONFIG_LINUX_USER) - &spr_read_generic, -#else - SPR_NOACCESS, -#endif - SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - pcc->pvr); - /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ - if (pcc->svr != POWERPC_SVR_NONE) { - if (pcc->svr & POWERPC_SVR_E500) { - spr_register(env, SPR_E500_SVR, "SVR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - pcc->svr & ~POWERPC_SVR_E500); - } else { - spr_register(env, SPR_SVR, "SVR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - pcc->svr); - } - } + register_generic_sprs(cpu); + /* PowerPC implementation specific initialisations (SPRs, timers, ...) */ (*pcc->init_proc)(env); diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index fcc83a7701..6538c56ab0 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu/main-loop.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "internal.h" @@ -360,12 +361,21 @@ static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp, target_ulong msr, } #endif -static void powerpc_set_excp_state(PowerPCCPU *cpu, - target_ulong vector, target_ulong msr) +static void powerpc_reset_excp_state(PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; + /* Reset exception state */ + cs->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; +} + +static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector, + target_ulong msr) +{ + CPUPPCState *env = &cpu->env; + assert((msr & env->msr_mask) == msr); /* @@ -376,21 +386,20 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, * will prevent setting of the HV bit which some exceptions might need * to do. */ + env->nip = vector; env->msr = msr; hreg_compute_hflags(env); - env->nip = vector; - /* Reset exception state */ - cs->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; - /* Reset the reservation */ - env->reserve_addr = -1; + powerpc_reset_excp_state(cpu); /* * Any interrupt is context synchronizing, check if TCG TLB needs * a delayed flush on ppc64 */ check_tlb_flush(env, false); + + /* Reset the reservation */ + env->reserve_addr = -1; } static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) @@ -471,8 +480,7 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_FP: if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { trace_ppc_excp_fp_ignore(); - cs->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; + powerpc_reset_excp_state(cpu); return; } env->spr[SPR_40x_ESR] = ESR_FP; @@ -609,8 +617,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_FP: if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { trace_ppc_excp_fp_ignore(); - cs->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; + powerpc_reset_excp_state(cpu); return; } @@ -783,8 +790,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_FP: if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { trace_ppc_excp_fp_ignore(); - cs->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; + powerpc_reset_excp_state(cpu); return; } @@ -969,8 +975,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_FP: if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { trace_ppc_excp_fp_ignore(); - cs->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; + powerpc_reset_excp_state(cpu); return; } @@ -1168,8 +1173,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_FP: if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { trace_ppc_excp_fp_ignore(); - cs->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; + powerpc_reset_excp_state(cpu); return; } @@ -1277,7 +1281,45 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) powerpc_set_excp_state(cpu, vector, new_msr); } +/* + * When running a nested HV guest under vhyp, external interrupts are + * delivered as HVIRT. + */ +static bool books_vhyp_promotes_external_to_hvirt(PowerPCCPU *cpu) +{ + if (cpu->vhyp) { + return vhyp_cpu_in_nested(cpu); + } + return false; +} + #ifdef TARGET_PPC64 +/* + * When running under vhyp, hcalls are always intercepted and sent to the + * vhc->hypercall handler. + */ +static bool books_vhyp_handles_hcall(PowerPCCPU *cpu) +{ + if (cpu->vhyp) { + return !vhyp_cpu_in_nested(cpu); + } + return false; +} + +/* + * When running a nested KVM HV guest under vhyp, HV exceptions are not + * delivered to the guest (because there is no concept of HV support), but + * rather they are sent tothe vhyp to exit from the L2 back to the L1 and + * return from the H_ENTER_NESTED hypercall. + */ +static bool books_vhyp_handles_hv_excp(PowerPCCPU *cpu) +{ + if (cpu->vhyp) { + return vhyp_cpu_in_nested(cpu); + } + return false; +} + static void powerpc_excp_books(PowerPCCPU *cpu, int excp) { CPUState *cs = CPU(cpu); @@ -1394,8 +1436,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_FP: if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { trace_ppc_excp_fp_ignore(); - cs->exception_index = POWERPC_EXCP_NONE; - env->error_code = 0; + powerpc_reset_excp_state(cpu); return; } @@ -1439,7 +1480,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) env->nip += 4; /* "PAPR mode" built-in hypercall emulation */ - if ((lev == 1) && cpu->vhyp) { + if ((lev == 1) && books_vhyp_handles_hcall(cpu)) { PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); vhc->hypercall(cpu->vhyp, cpu); @@ -1527,12 +1568,6 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) break; } - /* Sanity check */ - if (!(env->msr_mask & MSR_HVB) && srr0 == SPR_HSRR0) { - cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " - "no HV support\n", excp); - } - /* * Sort out endianness of interrupt, this differs depending on the * CPU, the HV mode, etc... @@ -1551,10 +1586,26 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) env->spr[srr1] = msr; } - /* This can update new_msr and vector if AIL applies */ - ppc_excp_apply_ail(cpu, excp, msr, &new_msr, &vector); + if ((new_msr & MSR_HVB) && books_vhyp_handles_hv_excp(cpu)) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + /* Deliver interrupt to L1 by returning from the H_ENTER_NESTED call */ + vhc->deliver_hv_excp(cpu, excp); - powerpc_set_excp_state(cpu, vector, new_msr); + powerpc_reset_excp_state(cpu); + + } else { + /* Sanity check */ + if (!(env->msr_mask & MSR_HVB) && srr0 == SPR_HSRR0) { + cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " + "no HV support\n", excp); + } + + /* This can update new_msr and vector if AIL applies */ + ppc_excp_apply_ail(cpu, excp, msr, &new_msr, &vector); + + powerpc_set_excp_state(cpu, vector, new_msr); + } } #else static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp) @@ -1674,7 +1725,11 @@ static void ppc_hw_interrupt(CPUPPCState *env) /* HEIC blocks delivery to the hypervisor */ if ((async_deliver && !(heic && msr_hv && !msr_pr)) || (env->has_hv_mode && msr_hv == 0 && !lpes0)) { - powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } return; } } @@ -1784,6 +1839,8 @@ void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) msr |= (1ULL << MSR_LE); } + /* Anything for nested required here? MSR[HV] bit? */ + powerpc_set_excp_state(cpu, vector, msr); } diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 38fcb5fe50..9a691d6833 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -24,6 +24,8 @@ #include "sysemu/kvm.h" #include "helper_regs.h" #include "power8-pmu.h" +#include "cpu-models.h" +#include "spr_common.h" /* Swap temporary saved registers with GPRs */ void hreg_swap_gpr_tgpr(CPUPPCState *env) @@ -302,3 +304,403 @@ void check_tlb_flush(CPUPPCState *env, bool global) } } #endif + +/** + * _spr_register + * + * Register an SPR with all the callbacks required for tcg, + * and the ID number for KVM. + * + * The reason for the conditional compilation is that the tcg functions + * may be compiled out, and the system kvm header may not be available + * for supplying the ID numbers. This is ugly, but the best we can do. + */ +void _spr_register(CPUPPCState *env, int num, const char *name, + USR_ARG(spr_callback *uea_read) + USR_ARG(spr_callback *uea_write) + SYS_ARG(spr_callback *oea_read) + SYS_ARG(spr_callback *oea_write) + SYS_ARG(spr_callback *hea_read) + SYS_ARG(spr_callback *hea_write) + KVM_ARG(uint64_t one_reg_id) + target_ulong initial_value) +{ + ppc_spr_t *spr = &env->spr_cb[num]; + + /* No SPR should be registered twice. */ + assert(spr->name == NULL); + assert(name != NULL); + + spr->name = name; + spr->default_value = initial_value; + env->spr[num] = initial_value; + +#ifdef CONFIG_TCG + spr->uea_read = uea_read; + spr->uea_write = uea_write; +# ifndef CONFIG_USER_ONLY + spr->oea_read = oea_read; + spr->oea_write = oea_write; + spr->hea_read = hea_read; + spr->hea_write = hea_write; +# endif +#endif +#ifdef CONFIG_KVM + spr->one_reg_id = one_reg_id; +#endif +} + +/* Generic PowerPC SPRs */ +void register_generic_sprs(PowerPCCPU *cpu) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + + /* Integer processing */ + spr_register(env, SPR_XER, "XER", + &spr_read_xer, &spr_write_xer, + &spr_read_xer, &spr_write_xer, + 0x00000000); + /* Branch control */ + spr_register(env, SPR_LR, "LR", + &spr_read_lr, &spr_write_lr, + &spr_read_lr, &spr_write_lr, + 0x00000000); + spr_register(env, SPR_CTR, "CTR", + &spr_read_ctr, &spr_write_ctr, + &spr_read_ctr, &spr_write_ctr, + 0x00000000); + /* Interrupt processing */ + spr_register(env, SPR_SRR0, "SRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SRR1, "SRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Processor control */ + spr_register(env, SPR_SPRG0, "SPRG0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG1, "SPRG1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG2, "SPRG2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG3, "SPRG3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_PVR, "PVR", + /* Linux permits userspace to read PVR */ +#if defined(CONFIG_LINUX_USER) + &spr_read_generic, +#else + SPR_NOACCESS, +#endif + SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + pcc->pvr); + + /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ + if (pcc->svr != POWERPC_SVR_NONE) { + if (pcc->svr & POWERPC_SVR_E500) { + spr_register(env, SPR_E500_SVR, "SVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + pcc->svr & ~POWERPC_SVR_E500); + } else { + spr_register(env, SPR_SVR, "SVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + pcc->svr); + } + } + + /* Time base */ + spr_register(env, SPR_VTBL, "TBL", + &spr_read_tbl, SPR_NOACCESS, + &spr_read_tbl, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_TBL, "TBL", + &spr_read_tbl, SPR_NOACCESS, + &spr_read_tbl, &spr_write_tbl, + 0x00000000); + spr_register(env, SPR_VTBU, "TBU", + &spr_read_tbu, SPR_NOACCESS, + &spr_read_tbu, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_TBU, "TBU", + &spr_read_tbu, SPR_NOACCESS, + &spr_read_tbu, &spr_write_tbu, + 0x00000000); +} + +void register_non_embedded_sprs(CPUPPCState *env) +{ + /* Exception processing */ + spr_register_kvm(env, SPR_DSISR, "DSISR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DSISR, 0x00000000); + spr_register_kvm(env, SPR_DAR, "DAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DAR, 0x00000000); + /* Timer */ + spr_register(env, SPR_DECR, "DECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_decr, &spr_write_decr, + 0x00000000); +} + +/* Storage Description Register 1 */ +void register_sdr1_sprs(CPUPPCState *env) +{ +#ifndef CONFIG_USER_ONLY + if (env->has_hv_mode) { + /* + * SDR1 is a hypervisor resource on CPUs which have a + * hypervisor mode + */ + spr_register_hv(env, SPR_SDR1, "SDR1", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_sdr1, + 0x00000000); + } else { + spr_register(env, SPR_SDR1, "SDR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_sdr1, + 0x00000000); + } +#endif +} + +/* BATs 0-3 */ +void register_low_BATs(CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + spr_register(env, SPR_IBAT0U, "IBAT0U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT0L, "IBAT0L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_IBAT1U, "IBAT1U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT1L, "IBAT1L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_IBAT2U, "IBAT2U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT2L, "IBAT2L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_IBAT3U, "IBAT3U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT3L, "IBAT3L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_DBAT0U, "DBAT0U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT0L, "DBAT0L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + spr_register(env, SPR_DBAT1U, "DBAT1U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT1L, "DBAT1L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + spr_register(env, SPR_DBAT2U, "DBAT2U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT2L, "DBAT2L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + spr_register(env, SPR_DBAT3U, "DBAT3U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT3L, "DBAT3L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + env->nb_BATs += 4; +#endif +} + +/* BATs 4-7 */ +void register_high_BATs(CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + spr_register(env, SPR_IBAT4U, "IBAT4U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT4L, "IBAT4L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_IBAT5U, "IBAT5U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT5L, "IBAT5L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_IBAT6U, "IBAT6U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT6L, "IBAT6L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_IBAT7U, "IBAT7U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT7L, "IBAT7L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_DBAT4U, "DBAT4U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT4L, "DBAT4L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + spr_register(env, SPR_DBAT5U, "DBAT5U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT5L, "DBAT5L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + spr_register(env, SPR_DBAT6U, "DBAT6U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT6L, "DBAT6L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + spr_register(env, SPR_DBAT7U, "DBAT7U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT7L, "DBAT7L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + env->nb_BATs += 4; +#endif +} + +/* Softare table search registers */ +void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) +{ +#if !defined(CONFIG_USER_ONLY) + env->nb_tlb = nb_tlbs; + env->nb_ways = nb_ways; + env->id_tlbs = 1; + env->tlb_type = TLB_6XX; + spr_register(env, SPR_DMISS, "DMISS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_DCMP, "DCMP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_HASH1, "HASH1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_HASH2, "HASH2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_IMISS, "IMISS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_ICMP, "ICMP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_RPA, "RPA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +#endif +} + +void register_thrm_sprs(CPUPPCState *env) +{ + /* Thermal management */ + spr_register(env, SPR_THRM1, "THRM1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_thrm, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_THRM2, "THRM2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_thrm, &spr_write_generic, + 0x00000000); + + spr_register(env, SPR_THRM3, "THRM3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_thrm, &spr_write_generic, + 0x00000000); +} + +void register_usprgh_sprs(CPUPPCState *env) +{ + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); +} diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 29e73a6ffd..06aa716cab 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index d4e16bd7db..67c38f065b 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -354,6 +354,24 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, return 0; } +/* + * The spapr vhc has a flat partition scope provided by qemu memory when + * not nested. + * + * When running a nested guest, the addressing is 2-level radix on top of the + * vhc memory, so it works practically identically to the bare metal 2-level + * radix. So that code is selected directly. A cleaner and more flexible nested + * hypervisor implementation would allow the vhc to provide a ->nested_xlate() + * function but that is not required for the moment. + */ +static bool vhyp_flat_addressing(PowerPCCPU *cpu) +{ + if (cpu->vhyp) { + return !vhyp_cpu_in_nested(cpu); + } + return false; +} + static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, MMUAccessType access_type, vaddr eaddr, uint64_t pid, @@ -385,7 +403,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, } prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset; - if (cpu->vhyp) { + if (vhyp_flat_addressing(cpu)) { prtbe0 = ldq_phys(cs->as, prtbe_addr); } else { /* @@ -411,7 +429,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, *g_page_size = PRTBE_R_GET_RTS(prtbe0); base_addr = prtbe0 & PRTBE_R_RPDB; nls = prtbe0 & PRTBE_R_RPDS; - if (msr_hv || cpu->vhyp) { + if (msr_hv || vhyp_flat_addressing(cpu)) { /* * Can treat process table addresses as real addresses */ @@ -515,7 +533,7 @@ static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr, relocation = !mmuidx_real(mmu_idx); /* HV or virtual hypervisor Real Mode Access */ - if (!relocation && (mmuidx_hv(mmu_idx) || cpu->vhyp)) { + if (!relocation && (mmuidx_hv(mmu_idx) || vhyp_flat_addressing(cpu))) { /* In real mode top 4 effective addr bits (mostly) ignored */ *raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL; @@ -552,17 +570,25 @@ static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr, if (cpu->vhyp) { PPCVirtualHypervisorClass *vhc; vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); - vhc->get_pate(cpu->vhyp, &pate); + if (!vhc->get_pate(cpu->vhyp, cpu, lpid, &pate)) { + if (guest_visible) { + ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr, + DSISR_R_BADCONFIG); + } + return false; + } } else { if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { if (guest_visible) { - ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE); + ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr, + DSISR_R_BADCONFIG); } return false; } if (!validate_pate(cpu, lpid, &pate)) { if (guest_visible) { - ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG); + ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr, + DSISR_R_BADCONFIG); } return false; } @@ -592,7 +618,7 @@ static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr, g_raddr = eaddr & R_EADDR_MASK; } - if (cpu->vhyp) { + if (vhyp_flat_addressing(cpu)) { *raddr = g_raddr; } else { /* diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_common.h similarity index 72% rename from target/ppc/spr_tcg.h rename to target/ppc/spr_common.h index df2abacc64..b5a5bc6895 100644 --- a/target/ppc/spr_tcg.h +++ b/target/ppc/spr_common.h @@ -16,11 +16,67 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#ifndef SPR_TCG_H -#define SPR_TCG_H +#ifndef SPR_COMMON_H +#define SPR_COMMON_H #define SPR_NOACCESS (&spr_noaccess) +#ifdef CONFIG_TCG +# define USR_ARG(X) X, +# ifdef CONFIG_USER_ONLY +# define SYS_ARG(X) +# else +# define SYS_ARG(X) X, +# endif +#else +# define USR_ARG(X) +# define SYS_ARG(X) +#endif +#ifdef CONFIG_KVM +# define KVM_ARG(X) X, +#else +# define KVM_ARG(X) +#endif + +typedef void spr_callback(DisasContext *, int, int); + +void _spr_register(CPUPPCState *env, int num, const char *name, + USR_ARG(spr_callback *uea_read) + USR_ARG(spr_callback *uea_write) + SYS_ARG(spr_callback *oea_read) + SYS_ARG(spr_callback *oea_write) + SYS_ARG(spr_callback *hea_read) + SYS_ARG(spr_callback *hea_write) + KVM_ARG(uint64_t one_reg_id) + target_ulong initial_value); + +/* spr_register_kvm_hv passes all required arguments. */ +#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ + _spr_register(env, num, name, \ + USR_ARG(uea_read) USR_ARG(uea_write) \ + SYS_ARG(oea_read) SYS_ARG(oea_write) \ + SYS_ARG(hea_read) SYS_ARG(hea_write) \ + KVM_ARG(one_reg_id) initial_value) + +/* spr_register_kvm duplicates the oea callbacks to the hea callbacks. */ +#define spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, one_reg_id, ival) \ + spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \ + oea_write, oea_read, oea_write, one_reg_id, ival) + +/* spr_register_hv and spr_register are similar, except there is no kvm id. */ +#define spr_register_hv(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, ival) \ + spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \ + oea_write, hea_read, hea_write, 0, ival) + +#define spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, ival) \ + spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, 0, ival) + /* prototypes for readers and writers for SPRs */ void spr_noaccess(DisasContext *ctx, int gprn, int sprn); void spr_read_generic(DisasContext *ctx, int gprn, int sprn); @@ -141,4 +197,13 @@ void spr_write_hmer(DisasContext *ctx, int sprn, int gprn); void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn); #endif +void register_low_BATs(CPUPPCState *env); +void register_high_BATs(CPUPPCState *env); +void register_sdr1_sprs(CPUPPCState *env); +void register_thrm_sprs(CPUPPCState *env); +void register_usprgh_sprs(CPUPPCState *env); +void register_non_embedded_sprs(CPUPPCState *env); +void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways); +void register_generic_sprs(PowerPCCPU *cpu); + #endif diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 2eaffd432a..ecc5a104e0 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -35,7 +35,7 @@ #include "exec/translator.h" #include "exec/log.h" #include "qemu/atomic128.h" -#include "spr_tcg.h" +#include "spr_common.h" #include "qemu/qemu-print.h" #include "qapi/error.h" diff --git a/target/riscv/csr.c b/target/riscv/csr.c index fe2c8dd40e..a938760a3f 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/timer.h" #include "cpu.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 657db84ef0..58adf9edf6 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -116,8 +116,6 @@ struct RXCPU { typedef RXCPU ArchCPU; -#define ENV_OFFSET offsetof(RXCPU, env) - #define RX_CPU_TYPE_SUFFIX "-" TYPE_RX_CPU #define RX_CPU_TYPE_NAME(model) model RX_CPU_TYPE_SUFFIX #define CPU_RESOLVING_TYPE TYPE_RX_CPU diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 11e06cc51f..17ae771939 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -19,6 +19,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "qemu/module.h" +#include "qemu/hw-version.h" #include "qemu/qemu-print.h" #ifndef CONFIG_USER_ONLY #include "sysemu/sysemu.h" diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c index 4e7648f301..be6c966cfa 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "s390x-internal.h" #include "exec/helper-proto.h" diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 406578d105..b5523ef3c7 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "s390x-internal.h" #include "tcg_s390x.h" diff --git a/target/sparc/helper.c b/target/sparc/helper.c index c7bcaa3a20..c4358bba84 100644 --- a/target/sparc/helper.c +++ b/target/sparc/helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" +#include "qemu/timer.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index a3e1cf9b6e..ec4fae78c3 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "tcg/tcg.h" #include "exec/helper-proto.h" diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index f2668389b0..346a6dfa35 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "qemu/qemu-print.h" diff --git a/target/tricore/helper.c b/target/tricore/helper.c index c5e997f321..1db32808e8 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -16,7 +16,7 @@ */ #include "qemu/osdep.h" - +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "fpu/softfloat-helpers.h" diff --git a/target/xtensa/dbg_helper.c b/target/xtensa/dbg_helper.c index be1f81107b..ce2a820c60 100644 --- a/target/xtensa/dbg_helper.c +++ b/target/xtensa/dbg_helper.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c index 9bc7f50d35..d4823a65cd 100644 --- a/target/xtensa/exc_helper.c +++ b/target/xtensa/exc_helper.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c index ba3c29d19d..d2a10cc797 100644 --- a/target/xtensa/fpu_helper.c +++ b/target/xtensa/fpu_helper.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index 29d216ec1b..e0a9caab4b 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "exec/gdbstub.h" diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c index 57e319a1af..fa66e8e867 100644 --- a/target/xtensa/mmu_helper.c +++ b/target/xtensa/mmu_helper.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/qemu-print.h" #include "qemu/units.h" diff --git a/target/xtensa/win_helper.c b/target/xtensa/win_helper.c index f6f96a64c3..5a1555360a 100644 --- a/target/xtensa/win_helper.c +++ b/target/xtensa/win_helper.c @@ -26,6 +26,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" diff --git a/tcg/region.c b/tcg/region.c index 9cc30d4922..72afb35738 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -24,6 +24,9 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "qemu/madvise.h" +#include "qemu/mprotect.h" +#include "qemu/cacheinfo.h" #include "qapi/error.h" #include "exec/exec-all.h" #include "tcg/tcg.h" diff --git a/tcg/tcg.c b/tcg/tcg.c index 7cdc082f60..754544595e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -36,6 +36,7 @@ #include "qemu/qemu-print.h" #include "qemu/timer.h" #include "qemu/cacheflush.h" +#include "qemu/cacheinfo.h" /* Note: the long term plan is to reduce the dependencies on the QEMU CPU definitions. Currently they are used for qemu_ld/st diff --git a/tests/Makefile.include b/tests/Makefile.include index 646c8b1334..e7153c8e91 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -150,7 +150,7 @@ check-acceptance: check-acceptance-deprecated-warning | check-avocado .PHONY: check-block check check-clean get-vm-images check: -ifeq ($(CONFIG_TOOLS)$(CONFIG_POSIX),yy) +ifneq ($(.check-block.deps),) check: check-block check-block: run-ninja $(if $(MAKE.n),,+)$(MESON) test $(MTESTARGS) $(.mtestargs) --verbose \ diff --git a/tests/check-block.sh b/tests/check-block.sh index 720a46bc36..18f7433901 100755 --- a/tests/check-block.sh +++ b/tests/check-block.sh @@ -18,10 +18,6 @@ skip() { exit 0 } -if grep -q "CONFIG_GPROF=y" config-host.mak 2>/dev/null ; then - skip "GPROF is enabled ==> Not running the qemu-iotests." -fi - # Disable tests with any sanitizer except for specific ones SANITIZE_FLAGS=$( grep "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ) ALLOWED_SANITIZE_FLAGS="safe-stack cfi-icall" diff --git a/tests/meson.build b/tests/meson.build index 079c8f3727..1d05109eb4 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -85,7 +85,7 @@ if 'CONFIG_TCG' in config_all subdir('fp') endif -if not get_option('tcg').disabled() +if get_option('tcg').allowed() if 'CONFIG_PLUGIN' in config_host subdir('plugin') endif diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build index 5be3c74127..9747bb68a5 100644 --- a/tests/qemu-iotests/meson.build +++ b/tests/qemu-iotests/meson.build @@ -1,4 +1,4 @@ -if have_tools and targetos != 'windows' +if have_tools and targetos != 'windows' and not get_option('gprof') qemu_iotests_binaries = [qemu_img, qemu_io, qemu_nbd, qsd] qemu_iotests_env = {'PYTHON': python.full_path()} qemu_iotests_formats = { diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index 0eace147b8..9a94273975 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -404,7 +404,10 @@ class TestRunner(ContextManager['TestRunner']): if res.status == 'fail': failed.append(name) if res.diff: - print('\n'.join(res.diff)) + if self.tap: + print('\n'.join(res.diff), file=sys.stderr) + else: + print('\n'.join(res.diff)) elif res.status == 'not run': notrun.append(name) elif res.status == 'pass': diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c index ad79bd4c14..404a92e132 100644 --- a/tests/qtest/device-plug-test.c +++ b/tests/qtest/device-plug-test.c @@ -63,7 +63,15 @@ static void wait_device_deleted_event(QTestState *qtest, const char *id) static void test_pci_unplug_request(void) { - QTestState *qtest = qtest_initf("-device virtio-mouse-pci,id=dev0"); + const char *arch = qtest_get_arch(); + const char *machine_addition = ""; + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + machine_addition = "-machine pc"; + } + + QTestState *qtest = qtest_initf("%s -device virtio-mouse-pci,id=dev0", + machine_addition); /* * Request device removal. As the guest is not running, the request won't @@ -79,8 +87,16 @@ static void test_pci_unplug_request(void) static void test_pci_unplug_json_request(void) { + const char *arch = qtest_get_arch(); + const char *machine_addition = ""; + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + machine_addition = "-machine pc"; + } + QTestState *qtest = qtest_initf( - "-device '{\"driver\": \"virtio-mouse-pci\", \"id\": \"dev0\"}'"); + "%s -device '{\"driver\": \"virtio-mouse-pci\", \"id\": \"dev0\"}'", + machine_addition); /* * Request device removal. As the guest is not running, the request won't diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c index 8d08ee9995..0cc18dfa4a 100644 --- a/tests/qtest/drive_del-test.c +++ b/tests/qtest/drive_del-test.c @@ -235,14 +235,21 @@ static void test_drive_del_device_del(void) static void test_cli_device_del(void) { QTestState *qts; + const char *arch = qtest_get_arch(); + const char *machine_addition = ""; + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + machine_addition = "-machine pc"; + } /* * -drive/-device and device_del. Start with a drive used by a * device that unplugs after reset. */ - qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," + qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://," "file.read-zeroes=on,format=raw" " -device virtio-blk-%s,drive=drive0,id=dev0", + machine_addition, qvirtio_get_dev_type()); device_del(qts, true); @@ -266,13 +273,19 @@ static void test_empty_device_del(void) static void test_device_add_and_del(void) { QTestState *qts; + const char *arch = qtest_get_arch(); + const char *machine_addition = ""; + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + machine_addition = "-machine pc"; + } /* * -drive/device_add and device_del. Start with a drive used by a * device that unplugs after reset. */ - qts = qtest_init("-drive if=none,id=drive0,file=null-co://," - "file.read-zeroes=on,format=raw"); + qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://," + "file.read-zeroes=on,format=raw", machine_addition); device_add(qts); device_del(qts, true); @@ -284,8 +297,14 @@ static void test_device_add_and_del(void) static void test_drive_add_device_add_and_del(void) { QTestState *qts; + const char *arch = qtest_get_arch(); + const char *machine_addition = ""; - qts = qtest_init(""); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + machine_addition = "-machine pc"; + } + + qts = qtest_init(machine_addition); /* * drive_add/device_add and device_del. The drive is used by a @@ -302,8 +321,14 @@ static void test_drive_add_device_add_and_del(void) static void test_blockdev_add_device_add_and_del(void) { QTestState *qts; + const char *arch = qtest_get_arch(); + const char *machine_addition = ""; - qts = qtest_init(""); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + machine_addition = "-machine pc"; + } + + qts = qtest_init(machine_addition); /* * blockdev_add/device_add and device_del. The it drive is used by a diff --git a/tests/qtest/erst-test.c b/tests/qtest/erst-test.c index c6a0ae4013..f94cd8dd8e 100644 --- a/tests/qtest/erst-test.c +++ b/tests/qtest/erst-test.c @@ -75,7 +75,7 @@ static inline uint64_t in_reg64(ERSTState *s, unsigned reg) uint64_t res; res = qpci_io_readq(s->dev, s->reg_bar, reg); - g_test_message("*%s -> %016llx", name, (unsigned long long)res); + g_test_message("*%s -> %016" PRIx64, name, res); return res; } diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c index 8f6eee84a4..b0d40012e6 100644 --- a/tests/qtest/fdc-test.c +++ b/tests/qtest/fdc-test.c @@ -598,7 +598,7 @@ int main(int argc, char **argv) /* Run the tests */ g_test_init(&argc, &argv, NULL); - qtest_start("-device floppy,id=floppy0"); + qtest_start("-machine pc -device floppy,id=floppy0"); qtest_irq_intercept_in(global_qtest, "ioapic"); qtest_add_func("/fdc/cmos", test_cmos); qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start); diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c index 771eaa741b..64023c0574 100644 --- a/tests/qtest/hd-geo-test.c +++ b/tests/qtest/hd-geo-test.c @@ -178,9 +178,15 @@ static int append_arg(int argc, char *argv[], int argv_sz, char *arg) static int setup_common(char *argv[], int argv_sz) { + int new_argc; memset(cur_ide, 0, sizeof(cur_ide)); - return append_arg(0, argv, argv_sz, - g_strdup("-nodefaults")); + new_argc = append_arg(0, argv, argv_sz, + g_strdup("-nodefaults")); + new_argc = append_arg(new_argc, argv, argv_sz, + g_strdup("-machine")); + new_argc = append_arg(new_argc, argv, argv_sz, + g_strdup("pc")); + return new_argc; } static void setup_mbr(int img_idx, MBRcontents mbr) @@ -697,7 +703,7 @@ static void test_override(TestArgs *args, CHSResult expected[]) joined_args = g_strjoinv(" ", args->argv); - qts = qtest_init(joined_args); + qts = qtest_initf("-machine pc %s", joined_args); fw_cfg = pc_fw_cfg_init(qts); read_bootdevices(fw_cfg, expected); @@ -833,7 +839,7 @@ static void test_override_scsi_hot_unplug(void) joined_args = g_strjoinv(" ", args->argv); - qts = qtest_init(joined_args); + qts = qtest_initf("-machine pc %s", joined_args); fw_cfg = pc_fw_cfg_init(qts); read_bootdevices(fw_cfg, expected); @@ -893,7 +899,7 @@ static void test_override_virtio_hot_unplug(void) joined_args = g_strjoinv(" ", args->argv); - qts = qtest_init(joined_args); + qts = qtest_initf("-machine pc %s", joined_args); fw_cfg = pc_fw_cfg_init(qts); read_bootdevices(fw_cfg, expected); diff --git a/tests/qtest/i440fx-test.c b/tests/qtest/i440fx-test.c index 1f57d9684b..6d7d4d8d8f 100644 --- a/tests/qtest/i440fx-test.c +++ b/tests/qtest/i440fx-test.c @@ -35,7 +35,7 @@ static QPCIBus *test_start_get_bus(const TestData *s) { char *cmdline; - cmdline = g_strdup_printf("-smp %d", s->num_cpus); + cmdline = g_strdup_printf("-machine pc -smp %d", s->num_cpus); qtest_start(cmdline); g_free(cmdline); return qpci_new_pc(global_qtest, NULL); diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index 3f8081e77d..19de3b4104 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -128,10 +128,11 @@ static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX"; static QTestState *ide_test_start(const char *cmdline_fmt, ...) { QTestState *qts; + g_autofree char *full_fmt = g_strdup_printf("-machine pc %s", cmdline_fmt); va_list ap; va_start(ap, cmdline_fmt); - qts = qtest_vinitf(cmdline_fmt, ap); + qts = qtest_vinitf(full_fmt, ap); va_end(ap); pc_alloc_init(&guest_malloc, qts, 0); @@ -701,7 +702,7 @@ static void test_flush(void) free_pci_device(dev); } -static void test_retry_flush(const char *machine) +static void test_pci_retry_flush(void) { QTestState *qts; QPCIDevice *dev; @@ -790,16 +791,6 @@ static void test_flush_empty_drive(void) ide_test_quit(qts); } -static void test_pci_retry_flush(void) -{ - test_retry_flush("pc"); -} - -static void test_isa_retry_flush(void) -{ - test_retry_flush("isapc"); -} - typedef struct Read10CDB { uint8_t opcode; uint8_t flags; @@ -1050,7 +1041,6 @@ int main(int argc, char **argv) qtest_add_func("/ide/flush/nodev", test_flush_nodev); qtest_add_func("/ide/flush/empty_drive", test_flush_empty_drive); qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush); - qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush); qtest_add_func("/ide/cdrom/pio", test_cdrom_pio); qtest_add_func("/ide/cdrom/pio_large", test_cdrom_pio_large); diff --git a/tests/qtest/ivshmem-test.c b/tests/qtest/ivshmem-test.c index fe94dd3b96..4e8af42a9d 100644 --- a/tests/qtest/ivshmem-test.c +++ b/tests/qtest/ivshmem-test.c @@ -385,7 +385,12 @@ static void test_ivshmem_hotplug(void) QTestState *qts; const char *arch = qtest_get_arch(); - qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1"); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1" + " -machine pc"); + } else { + qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1"); + } qtest_qmp_device_add(qts, "ivshmem-plain", "iv1", "{'addr': %s, 'memdev': 'mb1'}", diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c index b4e1143288..f51f0635cc 100644 --- a/tests/qtest/libqos/virtio-9p.c +++ b/tests/qtest/libqos/virtio-9p.c @@ -37,31 +37,23 @@ static char *concat_path(const char* a, const char* b) return g_build_filename(a, b, NULL); } -static void init_local_test_path(void) +void virtio_9p_create_local_test_dir(void) { - char *pwd = g_get_current_dir(); + g_assert(local_test_path == NULL); + struct stat st; + g_autofree char *pwd = g_get_current_dir(); + /* + * template gets cached into local_test_path and freed in + * virtio_9p_remove_local_test_dir(). + */ char *template = concat_path(pwd, "qtest-9p-local-XXXXXX"); + local_test_path = mkdtemp(template); if (!local_test_path) { g_test_message("mkdtemp('%s') failed: %s", template, strerror(errno)); } - g_assert(local_test_path); - g_free(pwd); -} - -void virtio_9p_create_local_test_dir(void) -{ - struct stat st; - int res; - - init_local_test_path(); g_assert(local_test_path != NULL); - res = mkdir(local_test_path, 0777); - if (res < 0) { - g_test_message("mkdir('%s') failed: %s", local_test_path, - strerror(errno)); - } /* ensure test directory exists now ... */ g_assert(stat(local_test_path, &st) == 0); @@ -72,12 +64,13 @@ void virtio_9p_create_local_test_dir(void) void virtio_9p_remove_local_test_dir(void) { g_assert(local_test_path != NULL); - char *cmd = g_strdup_printf("rm -fr '%s'\n", local_test_path); + g_autofree char *cmd = g_strdup_printf("rm -fr '%s'\n", local_test_path); int res = system(cmd); if (res < 0) { /* ignore error, dummy check to prevent compiler error */ } - g_free(cmd); + g_free(local_test_path); + local_test_path = NULL; } char *virtio_9p_test_path(const char *path) @@ -221,8 +214,8 @@ static void *virtio_9p_pci_create(void *pci_bus, QGuestAllocator *t_alloc, static void regex_replace(GString *haystack, const char *pattern, const char *replace_fmt, ...) { - GRegex *regex; - char *replace, *s; + g_autoptr(GRegex) regex = NULL; + g_autofree char *replace = NULL, *s = NULL; va_list argp; va_start(argp, replace_fmt); @@ -232,9 +225,6 @@ static void regex_replace(GString *haystack, const char *pattern, regex = g_regex_new(pattern, 0, 0, NULL); s = g_regex_replace(regex, haystack->str, -1, 0, replace, 0, NULL); g_string_assign(haystack, s); - g_free(s); - g_regex_unref(regex); - g_free(replace); } void virtio_9p_assign_local_driver(GString *cmd_line, const char *args) diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c index 2a4568cd7d..ee30f54796 100644 --- a/tests/qtest/vhost-user-test.c +++ b/tests/qtest/vhost-user-test.c @@ -42,7 +42,7 @@ #define QEMU_CMD_MEMFD " -m %d -object memory-backend-memfd,id=mem,size=%dM," \ " -numa node,memdev=mem" #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s" -#define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce" +#define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce=on" #define HUGETLBFS_MAGIC 0x958458f6 diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c index 41fed41de1..502e5ad0c7 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -84,7 +84,7 @@ static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; size_t tag_len = qvirtio_config_readw(v9p->vdev, 0); - char *tag; + g_autofree char *tag = NULL; int i; g_assert_cmpint(tag_len, ==, strlen(MOUNT_TAG)); @@ -94,7 +94,6 @@ static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) tag[i] = qvirtio_config_readb(v9p->vdev, i + 2); } g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len); - g_free(tag); } #define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ @@ -580,7 +579,7 @@ static void do_version(QVirtio9P *v9p) { const char *version = "9P2000.L"; uint16_t server_len; - char *server_version; + g_autofree char *server_version = NULL; P9Req *req; req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG); @@ -588,8 +587,6 @@ static void do_version(QVirtio9P *v9p) v9fs_rversion(req, &server_len, &server_version); g_assert_cmpmem(server_version, server_len, version, strlen(version)); - - g_free(server_version); } /* utility function: walk to requested dir and return fid for that dir */ @@ -637,7 +634,7 @@ static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc) alloc = t_alloc; char *wnames[P9_MAXWELEM]; uint16_t nwqid; - v9fs_qid *wqid; + g_autofree v9fs_qid *wqid = NULL; int i; P9Req *req; @@ -655,8 +652,6 @@ static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc) for (i = 0; i < P9_MAXWELEM; i++) { g_free(wnames[i]); } - - g_free(wqid); } static bool fs_dirents_contain_name(struct V9fsDirent *e, const char* name) @@ -872,9 +867,9 @@ static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) g_assert_cmpint(fs_dirents_contain_name(entries, "."), ==, true); g_assert_cmpint(fs_dirents_contain_name(entries, ".."), ==, true); for (int i = 0; i < QTEST_V9FS_SYNTH_READDIR_NFILES; ++i) { - char *name = g_strdup_printf(QTEST_V9FS_SYNTH_READDIR_FILE, i); + g_autofree char *name = + g_strdup_printf(QTEST_V9FS_SYNTH_READDIR_FILE, i); g_assert_cmpint(fs_dirents_contain_name(entries, name), ==, true); - g_free(name); } v9fs_free_dirents(entries); @@ -984,7 +979,8 @@ static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; char *const wnames[] = { g_strdup("..") }; - v9fs_qid root_qid, *wqid; + v9fs_qid root_qid; + g_autofree v9fs_qid *wqid = NULL; P9Req *req; do_version(v9p); @@ -998,7 +994,6 @@ static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc) g_assert_cmpmem(&root_qid, 13, wqid[0], 13); - g_free(wqid); g_free(wnames[0]); } @@ -1027,7 +1022,7 @@ static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc) alloc = t_alloc; static const uint32_t write_count = P9_MAX_SIZE / 2; char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; - char *buf = g_malloc0(write_count); + g_autofree char *buf = g_malloc0(write_count); uint32_t count; P9Req *req; @@ -1045,7 +1040,6 @@ static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc) v9fs_rwrite(req, &count); g_assert_cmpint(count, ==, write_count); - g_free(buf); g_free(wnames[0]); } @@ -1125,7 +1119,7 @@ static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc) static void do_mkdir(QVirtio9P *v9p, const char *path, const char *cname) { - char *const name = g_strdup(cname); + g_autofree char *name = g_strdup(cname); uint32_t fid; P9Req *req; @@ -1134,15 +1128,13 @@ static void do_mkdir(QVirtio9P *v9p, const char *path, const char *cname) req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0); v9fs_req_wait_for_reply(req, NULL); v9fs_rmkdir(req, NULL); - - g_free(name); } /* create a regular file with Tlcreate and return file's fid */ static uint32_t do_lcreate(QVirtio9P *v9p, const char *path, const char *cname) { - char *const name = g_strdup(cname); + g_autofree char *name = g_strdup(cname); uint32_t fid; P9Req *req; @@ -1152,7 +1144,6 @@ static uint32_t do_lcreate(QVirtio9P *v9p, const char *path, v9fs_req_wait_for_reply(req, NULL); v9fs_rlcreate(req, NULL, NULL); - g_free(name); return fid; } @@ -1160,8 +1151,8 @@ static uint32_t do_lcreate(QVirtio9P *v9p, const char *path, static void do_symlink(QVirtio9P *v9p, const char *path, const char *clink, const char *to) { - char *const name = g_strdup(clink); - char *const dst = g_strdup(to); + g_autofree char *name = g_strdup(clink); + g_autofree char *dst = g_strdup(to); uint32_t fid; P9Req *req; @@ -1170,9 +1161,6 @@ static void do_symlink(QVirtio9P *v9p, const char *path, const char *clink, req = v9fs_tsymlink(v9p, fid, name, dst, 0, 0); v9fs_req_wait_for_reply(req, NULL); v9fs_rsymlink(req, NULL); - - g_free(dst); - g_free(name); } /* create a hard link named @a clink in directory @a path pointing to @a to */ @@ -1193,7 +1181,7 @@ static void do_hardlink(QVirtio9P *v9p, const char *path, const char *clink, static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath, uint32_t flags) { - char *const name = g_strdup(rpath); + g_autofree char *name = g_strdup(rpath); uint32_t fid; P9Req *req; @@ -1202,8 +1190,6 @@ static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath, req = v9fs_tunlinkat(v9p, fid, name, flags, 0); v9fs_req_wait_for_reply(req, NULL); v9fs_runlinkat(req); - - g_free(name); } static void fs_readdir_split_128(void *obj, void *data, @@ -1235,8 +1221,8 @@ static void fs_create_dir(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st; - char *root_path = virtio_9p_test_path(""); - char *new_dir = virtio_9p_test_path("01"); + g_autofree char *root_path = virtio_9p_test_path(""); + g_autofree char *new_dir = virtio_9p_test_path("01"); g_assert(root_path != NULL); @@ -1247,9 +1233,6 @@ static void fs_create_dir(void *obj, void *data, QGuestAllocator *t_alloc) g_assert(stat(new_dir, &st) == 0); /* ... and is actually a directory */ g_assert((st.st_mode & S_IFMT) == S_IFDIR); - - g_free(new_dir); - g_free(root_path); } static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) @@ -1257,8 +1240,8 @@ static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st; - char *root_path = virtio_9p_test_path(""); - char *new_dir = virtio_9p_test_path("02"); + g_autofree char *root_path = virtio_9p_test_path(""); + g_autofree char *new_dir = virtio_9p_test_path("02"); g_assert(root_path != NULL); @@ -1273,9 +1256,6 @@ static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) do_unlinkat(v9p, "/", "02", AT_REMOVEDIR); /* directory should be gone now */ g_assert(stat(new_dir, &st) != 0); - - g_free(new_dir); - g_free(root_path); } static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) @@ -1283,7 +1263,7 @@ static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st; - char *new_file = virtio_9p_test_path("03/1st_file"); + g_autofree char *new_file = virtio_9p_test_path("03/1st_file"); do_attach(v9p); do_mkdir(v9p, "/", "03"); @@ -1293,8 +1273,6 @@ static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) g_assert(stat(new_file, &st) == 0); /* ... and is a regular file */ g_assert((st.st_mode & S_IFMT) == S_IFREG); - - g_free(new_file); } static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) @@ -1302,7 +1280,7 @@ static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st; - char *new_file = virtio_9p_test_path("04/doa_file"); + g_autofree char *new_file = virtio_9p_test_path("04/doa_file"); do_attach(v9p); do_mkdir(v9p, "/", "04"); @@ -1316,8 +1294,6 @@ static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) do_unlinkat(v9p, "04", "doa_file", 0); /* file should be gone now */ g_assert(stat(new_file, &st) != 0); - - g_free(new_file); } static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc) @@ -1325,8 +1301,8 @@ static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st; - char *real_file = virtio_9p_test_path("05/real_file"); - char *symlink_file = virtio_9p_test_path("05/symlink_file"); + g_autofree char *real_file = virtio_9p_test_path("05/real_file"); + g_autofree char *symlink_file = virtio_9p_test_path("05/symlink_file"); do_attach(v9p); do_mkdir(v9p, "/", "05"); @@ -1338,9 +1314,6 @@ static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc) /* check if created link exists now */ g_assert(stat(symlink_file, &st) == 0); - - g_free(symlink_file); - g_free(real_file); } static void fs_unlinkat_symlink(void *obj, void *data, @@ -1349,8 +1322,8 @@ static void fs_unlinkat_symlink(void *obj, void *data, QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st; - char *real_file = virtio_9p_test_path("06/real_file"); - char *symlink_file = virtio_9p_test_path("06/symlink_file"); + g_autofree char *real_file = virtio_9p_test_path("06/real_file"); + g_autofree char *symlink_file = virtio_9p_test_path("06/symlink_file"); do_attach(v9p); do_mkdir(v9p, "/", "06"); @@ -1364,9 +1337,6 @@ static void fs_unlinkat_symlink(void *obj, void *data, do_unlinkat(v9p, "06", "symlink_file", 0); /* symlink should be gone now */ g_assert(stat(symlink_file, &st) != 0); - - g_free(symlink_file); - g_free(real_file); } static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc) @@ -1374,8 +1344,8 @@ static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc) QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st_real, st_link; - char *real_file = virtio_9p_test_path("07/real_file"); - char *hardlink_file = virtio_9p_test_path("07/hardlink_file"); + g_autofree char *real_file = virtio_9p_test_path("07/real_file"); + g_autofree char *hardlink_file = virtio_9p_test_path("07/hardlink_file"); do_attach(v9p); do_mkdir(v9p, "/", "07"); @@ -1391,9 +1361,6 @@ static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc) g_assert((st_link.st_mode & S_IFMT) == S_IFREG); g_assert(st_link.st_dev == st_real.st_dev); g_assert(st_link.st_ino == st_real.st_ino); - - g_free(hardlink_file); - g_free(real_file); } static void fs_unlinkat_hardlink(void *obj, void *data, @@ -1402,8 +1369,8 @@ static void fs_unlinkat_hardlink(void *obj, void *data, QVirtio9P *v9p = obj; alloc = t_alloc; struct stat st_real, st_link; - char *real_file = virtio_9p_test_path("08/real_file"); - char *hardlink_file = virtio_9p_test_path("08/hardlink_file"); + g_autofree char *real_file = virtio_9p_test_path("08/real_file"); + g_autofree char *hardlink_file = virtio_9p_test_path("08/hardlink_file"); do_attach(v9p); do_mkdir(v9p, "/", "08"); @@ -1419,9 +1386,6 @@ static void fs_unlinkat_hardlink(void *obj, void *data, g_assert(stat(hardlink_file, &st_link) != 0); /* and old file should still exist */ g_assert(stat(real_file, &st_real) == 0); - - g_free(hardlink_file); - g_free(real_file); } static void *assign_9p_local_driver(GString *cmd_line, void *arg) diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c index 22ad54bb95..80292eecf6 100644 --- a/tests/qtest/virtio-net-failover.c +++ b/tests/qtest/virtio-net-failover.c @@ -18,6 +18,8 @@ #include "libqos/virtio-pci.h" #include "hw/pci/pci.h" +#define VIRTIO_NET_F_STANDBY 62 + #define ACPI_PCIHP_ADDR_ICH9 0x0cc0 #define PCI_EJ_BASE 0x0008 #define PCI_SEL_BASE 0x0010 @@ -224,88 +226,27 @@ static char *get_mac(QTestState *qts, const char *name) return mac; } -static void check_one_card(QTestState *qts, bool present, - const char *id, const char *mac) -{ - QDict *device; - QDict *bus; - char *addr; - - bus = get_bus(qts, 0); - device = find_device(bus, id); - if (present) { - char *path; - - g_assert_nonnull(device); - qobject_unref(device); - - path = g_strdup_printf("/machine/peripheral/%s", id); - addr = get_mac(qts, path); - g_free(path); - g_assert_cmpstr(mac, ==, addr); - g_free(addr); - } else { - g_assert_null(device); - } - - qobject_unref(bus); -} - -static void test_on(void) -{ - QTestState *qts; - - qts = machine_start(BASE_MACHINE - "-netdev user,id=hs0 " - "-device virtio-net,bus=root0,id=standby0," - "failover=on,netdev=hs0,mac="MAC_STANDBY0" " - "-device virtio-net,bus=root1,id=primary0," - "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, - 2); - - check_one_card(qts, true, "standby0", MAC_STANDBY0); - check_one_card(qts, false, "primary0", MAC_PRIMARY0); - - machine_stop(qts); -} - -static void test_on_mismatch(void) -{ - QTestState *qts; - - qts = machine_start(BASE_MACHINE - "-netdev user,id=hs0 " - "-device virtio-net,bus=root0,id=standby0," - "failover=on,netdev=hs0,mac="MAC_STANDBY0" " - "-netdev user,id=hs1 " - "-device virtio-net,bus=root1,id=primary0," - "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0, - 2); - - check_one_card(qts, true, "standby0", MAC_STANDBY0); - check_one_card(qts, true, "primary0", MAC_PRIMARY0); - - machine_stop(qts); -} - -static void test_off(void) -{ - QTestState *qts; - - qts = machine_start(BASE_MACHINE - "-netdev user,id=hs0 " - "-device virtio-net,bus=root0,id=standby0," - "failover=off,netdev=hs0,mac="MAC_STANDBY0" " - "-netdev user,id=hs1 " - "-device virtio-net,bus=root1,id=primary0," - "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, - 2); - - check_one_card(qts, true, "standby0", MAC_STANDBY0); - check_one_card(qts, true, "primary0", MAC_PRIMARY0); - - machine_stop(qts); -} +#define check_one_card(qts, present, id, mac) \ +do { \ + QDict *device; \ + QDict *bus; \ + char *addr; \ + bus = get_bus(qts, 0); \ + device = find_device(bus, id); \ + if (present) { \ + char *path; \ + g_assert_nonnull(device); \ + qobject_unref(device); \ + path = g_strdup_printf("/machine/peripheral/%s", id); \ + addr = get_mac(qts, path); \ + g_free(path); \ + g_assert_cmpstr(mac, ==, addr); \ + g_free(addr); \ + } else { \ + g_assert_null(device); \ + } \ + qobject_unref(bus); \ +} while (0) static QDict *get_failover_negociated_event(QTestState *qts) { @@ -323,33 +264,120 @@ static QDict *get_failover_negociated_event(QTestState *qts) return data; } -static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot, - const char *id) +static QVirtioPCIDevice *start_virtio_net_internal(QTestState *qts, + int bus, int slot, + uint64_t *features) { QVirtioPCIDevice *dev; - uint64_t features; QPCIAddress addr; - QDict *resp; addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0); dev = virtio_pci_new(pcibus, &addr); g_assert_nonnull(dev); qvirtio_pci_device_enable(dev); qvirtio_start_device(&dev->vdev); - features = qvirtio_get_features(&dev->vdev); - features = features & ~(QVIRTIO_F_BAD_FEATURE | - (1ull << VIRTIO_RING_F_INDIRECT_DESC) | - (1ull << VIRTIO_RING_F_EVENT_IDX)); - qvirtio_set_features(&dev->vdev, features); + *features &= qvirtio_get_features(&dev->vdev); + qvirtio_set_features(&dev->vdev, *features); qvirtio_set_driver_ok(&dev->vdev); + return dev; +} - resp = get_failover_negociated_event(qts); - g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id); - qobject_unref(resp); +static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot, + const char *id, bool failover) +{ + QVirtioPCIDevice *dev; + uint64_t features; + + features = ~(QVIRTIO_F_BAD_FEATURE | + (1ull << VIRTIO_RING_F_INDIRECT_DESC) | + (1ull << VIRTIO_RING_F_EVENT_IDX)); + + dev = start_virtio_net_internal(qts, bus, slot, &features); + + g_assert(!!(features & (1ull << VIRTIO_NET_F_STANDBY)) == failover); + + if (failover) { + QDict *resp; + + resp = get_failover_negociated_event(qts); + g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id); + qobject_unref(resp); + } return dev; } +static void test_on(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=on,netdev=hs0,mac="MAC_STANDBY0" " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, + 2); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + machine_stop(qts); +} + +static void test_on_mismatch(void) +{ + QTestState *qts; + QVirtioPCIDevice *vdev; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=on,netdev=hs0,mac="MAC_STANDBY0" " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0, + 2); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + vdev = start_virtio_net(qts, 1, 0, "standby0", true); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + qos_object_destroy((QOSGraphObject *)vdev); + machine_stop(qts); +} + +static void test_off(void) +{ + QTestState *qts; + QVirtioPCIDevice *vdev; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=off,netdev=hs0,mac="MAC_STANDBY0" " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, + 2); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + vdev = start_virtio_net(qts, 1, 0, "standby0", false); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + qos_object_destroy((QOSGraphObject *)vdev); + machine_stop(qts); +} + static void test_enabled(void) { QTestState *qts; @@ -367,7 +395,7 @@ static void test_enabled(void) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); @@ -376,6 +404,38 @@ static void test_enabled(void) machine_stop(qts); } +static void test_guest_off(void) +{ + QTestState *qts; + QVirtioPCIDevice *vdev; + uint64_t features; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=on,netdev=hs0,mac="MAC_STANDBY0" " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ", + 2); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + features = ~(QVIRTIO_F_BAD_FEATURE | + (1ull << VIRTIO_RING_F_INDIRECT_DESC) | + (1ull << VIRTIO_RING_F_EVENT_IDX) | + (1ull << VIRTIO_NET_F_STANDBY)); + + vdev = start_virtio_net_internal(qts, 1, 0, &features); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qos_object_destroy((QOSGraphObject *)vdev); + machine_stop(qts); +} + static void test_hotplug_1(void) { QTestState *qts; @@ -390,7 +450,7 @@ static void test_hotplug_1(void) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); @@ -432,7 +492,7 @@ static void test_hotplug_1_reverse(void) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); @@ -463,7 +523,7 @@ static void test_hotplug_2(void) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); @@ -519,7 +579,7 @@ static void test_hotplug_2_reverse(void) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); @@ -584,7 +644,7 @@ static void test_migrate_out(gconstpointer opaque) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); @@ -755,6 +815,364 @@ static void test_migrate_in(gconstpointer opaque) machine_stop(qts); } +static void test_off_migrate_out(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args, *ret; + g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); + const gchar *status; + QVirtioPCIDevice *vdev; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 ", + 2); + + check_one_card(qts, false, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'off'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + vdev = start_virtio_net(qts, 1, 0, "standby0", false); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + while (true) { + ret = migrate_status(qts); + + status = qdict_get_str(ret, "status"); + if (strcmp(status, "completed") == 0) { + qobject_unref(ret); + break; + } + g_assert_cmpstr(status, !=, "failed"); + g_assert_cmpstr(status, !=, "cancelling"); + g_assert_cmpstr(status, !=, "cancelled"); + qobject_unref(ret); + } + + qtest_qmp_eventwait(qts, "STOP"); + + qos_object_destroy((QOSGraphObject *)vdev); + machine_stop(qts); +} + +static void test_off_migrate_in(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args, *ret; + g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 " + "-incoming defer ", + 2); + + check_one_card(qts, false, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'off'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", + args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + resp = get_migration_event(qts); + g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); + qobject_unref(resp); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + qtest_qmp_eventwait(qts, "RESUME"); + + ret = migrate_status(qts); + g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed"); + qobject_unref(ret); + + machine_stop(qts); +} + +static void test_guest_off_migrate_out(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args, *ret; + g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); + const gchar *status; + QVirtioPCIDevice *vdev; + uint64_t features; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 ", + 2); + + check_one_card(qts, false, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + features = ~(QVIRTIO_F_BAD_FEATURE | + (1ull << VIRTIO_RING_F_INDIRECT_DESC) | + (1ull << VIRTIO_RING_F_EVENT_IDX) | + (1ull << VIRTIO_NET_F_STANDBY)); + + vdev = start_virtio_net_internal(qts, 1, 0, &features); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + while (true) { + ret = migrate_status(qts); + + status = qdict_get_str(ret, "status"); + if (strcmp(status, "completed") == 0) { + qobject_unref(ret); + break; + } + g_assert_cmpstr(status, !=, "failed"); + g_assert_cmpstr(status, !=, "cancelling"); + g_assert_cmpstr(status, !=, "cancelled"); + qobject_unref(ret); + } + + qtest_qmp_eventwait(qts, "STOP"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qos_object_destroy((QOSGraphObject *)vdev); + machine_stop(qts); +} + +static void test_guest_off_migrate_in(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args, *ret; + g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 " + "-incoming defer ", + 2); + + check_one_card(qts, false, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", + args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + resp = get_migration_event(qts); + g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); + qobject_unref(resp); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_eventwait(qts, "RESUME"); + + ret = migrate_status(qts); + g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed"); + qobject_unref(ret); + + machine_stop(qts); +} + +static void test_migrate_guest_off_abort(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args, *ret; + g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); + const gchar *status; + QVirtioPCIDevice *vdev; + uint64_t features; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 ", + 2); + + check_one_card(qts, false, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + features = ~(QVIRTIO_F_BAD_FEATURE | + (1ull << VIRTIO_RING_F_INDIRECT_DESC) | + (1ull << VIRTIO_RING_F_EVENT_IDX) | + (1ull << VIRTIO_NET_F_STANDBY)); + + vdev = start_virtio_net_internal(qts, 1, 0, &features); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + while (true) { + ret = migrate_status(qts); + + status = qdict_get_str(ret, "status"); + if (strcmp(status, "active") == 0) { + qobject_unref(ret); + break; + } + g_assert_cmpstr(status, !=, "failed"); + qobject_unref(ret); + } + + resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + while (true) { + ret = migrate_status(qts); + + status = qdict_get_str(ret, "status"); + if (strcmp(status, "cancelled") == 0) { + qobject_unref(ret); + break; + } + g_assert_cmpstr(status, !=, "failed"); + g_assert_cmpstr(status, !=, "active"); + qobject_unref(ret); + } + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qos_object_destroy((QOSGraphObject *)vdev); + machine_stop(qts); +} + static void test_migrate_abort_wait_unplug(gconstpointer opaque) { QTestState *qts; @@ -780,7 +1198,7 @@ static void test_migrate_abort_wait_unplug(gconstpointer opaque) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); @@ -870,7 +1288,7 @@ static void test_migrate_abort_active(gconstpointer opaque) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); @@ -938,6 +1356,91 @@ static void test_migrate_abort_active(gconstpointer opaque) machine_stop(qts); } +static void test_migrate_off_abort(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args, *ret; + g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); + const gchar *status; + QVirtioPCIDevice *vdev; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 ", + 2); + + check_one_card(qts, false, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'off'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + vdev = start_virtio_net(qts, 1, 0, "standby0", false); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, false, "primary0", MAC_PRIMARY0); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY0"'}"); + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + while (true) { + ret = migrate_status(qts); + + status = qdict_get_str(ret, "status"); + if (strcmp(status, "active") == 0) { + qobject_unref(ret); + break; + } + g_assert_cmpstr(status, !=, "failed"); + qobject_unref(ret); + } + + resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + while (true) { + ret = migrate_status(qts); + + status = qdict_get_str(ret, "status"); + if (strcmp(status, "cancelled") == 0) { + qobject_unref(ret); + break; + } + g_assert_cmpstr(status, !=, "failed"); + g_assert_cmpstr(status, !=, "active"); + qobject_unref(ret); + } + + check_one_card(qts, true, "standby0", MAC_STANDBY0); + check_one_card(qts, true, "primary0", MAC_PRIMARY0); + + qos_object_destroy((QOSGraphObject *)vdev); + machine_stop(qts); +} + static void test_migrate_abort_timeout(gconstpointer opaque) { QTestState *qts; @@ -964,7 +1467,7 @@ static void test_migrate_abort_timeout(gconstpointer opaque) check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); - vdev = start_virtio_net(qts, 1, 0, "standby0"); + vdev = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, false, "primary0", MAC_PRIMARY0); @@ -1075,7 +1578,7 @@ static void test_multi_out(gconstpointer opaque) check_one_card(qts, false, "standby1", MAC_STANDBY1); check_one_card(qts, false, "primary1", MAC_PRIMARY1); - vdev0 = start_virtio_net(qts, 1, 0, "standby0"); + vdev0 = start_virtio_net(qts, 1, 0, "standby0", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); @@ -1106,7 +1609,7 @@ static void test_multi_out(gconstpointer opaque) check_one_card(qts, true, "standby1", MAC_STANDBY1); check_one_card(qts, false, "primary1", MAC_PRIMARY1); - vdev1 = start_virtio_net(qts, 3, 0, "standby1"); + vdev1 = start_virtio_net(qts, 3, 0, "standby1", true); check_one_card(qts, true, "standby0", MAC_STANDBY0); check_one_card(qts, true, "primary0", MAC_PRIMARY0); @@ -1315,6 +1818,7 @@ int main(int argc, char **argv) g_assert_true(ret >= 0); close(ret); + /* parameters tests */ qtest_add_func("failover-virtio-net/params/error/id", test_error_id); qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie); qtest_add_func("failover-virtio-net/params/on", test_on); @@ -1322,16 +1826,33 @@ int main(int argc, char **argv) test_on_mismatch); qtest_add_func("failover-virtio-net/params/off", test_off); qtest_add_func("failover-virtio-net/params/enabled", test_enabled); - qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1); - qtest_add_func("failover-virtio-net/hotplug_1_reverse", + qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off); + + /* hotplug tests */ + qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1); + qtest_add_func("failover-virtio-net/hotplug/1_reverse", test_hotplug_1_reverse); - qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2); - qtest_add_func("failover-virtio-net/hotplug_2_reverse", + qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2); + qtest_add_func("failover-virtio-net/hotplug/2_reverse", test_hotplug_2_reverse); - qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile, + + /* migration tests */ + qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile, test_migrate_out); - qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile, + qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile, test_migrate_in); + qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile, + test_off_migrate_out); + qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile, + test_off_migrate_in); + qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile, + test_migrate_off_abort); + qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile, + test_guest_off_migrate_out); + qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile, + test_guest_off_migrate_in); + qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile, + test_migrate_guest_off_abort); qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug", tmpfile, test_migrate_abort_wait_unplug); qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile, @@ -1340,9 +1861,9 @@ int main(int argc, char **argv) qtest_add_data_func("failover-virtio-net/migrate/abort/timeout", tmpfile, test_migrate_abort_timeout); } - qtest_add_data_func("failover-virtio-net/multi/out", + qtest_add_data_func("failover-virtio-net/migrate/multi/out", tmpfile, test_multi_out); - qtest_add_data_func("failover-virtio-net/multi/in", + qtest_add_data_func("failover-virtio-net/migrate/multi/in", tmpfile, test_multi_in); ret = g_test_run(); diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 64a5e7bfde..96b295263e 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -53,6 +53,10 @@ if have_system or have_tools tests += { 'test-qmp-event': [testqapi], } + + if seccomp.found() + tests += {'test-seccomp': ['../../softmmu/qemu-seccomp.c', seccomp]} + endif endif if have_block @@ -106,7 +110,7 @@ if have_block if 'CONFIG_POSIX' in config_host tests += {'test-image-locking': [testblock]} endif - if 'CONFIG_REPLICATION' in config_host + if config_host_data.get('CONFIG_REPLICATION') tests += {'test-replication': [testblock]} endif if nettle.found() or gcrypt.found() @@ -149,9 +153,7 @@ if have_system endif endif -if 'CONFIG_TSAN' not in config_host and \ - 'CONFIG_GUEST_AGENT' in config_host and \ - 'CONFIG_LINUX' in config_host +if have_ga and targetos == 'linux' and 'CONFIG_TSAN' not in config_host tests += {'test-qga': ['../qtest/libqtest.c']} test_deps += {'test-qga': qga} endif diff --git a/tests/unit/test-seccomp.c b/tests/unit/test-seccomp.c new file mode 100644 index 0000000000..3d7771e46c --- /dev/null +++ b/tests/unit/test-seccomp.c @@ -0,0 +1,269 @@ +/* + * QEMU seccomp test suite + * + * Copyright (c) 2021 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "qemu/config-file.h" +#include "qemu/option.h" +#include "sysemu/seccomp.h" +#include "qapi/error.h" +#include "qemu/module.h" + +#include +#include + +static void test_seccomp_helper(const char *args, bool killed, + int errnum, int (*doit)(void)) +{ + if (g_test_subprocess()) { + QemuOptsList *olist; + QemuOpts *opts; + int ret; + + module_call_init(MODULE_INIT_OPTS); + olist = qemu_find_opts("sandbox"); + g_assert(olist != NULL); + + opts = qemu_opts_parse_noisily(olist, args, true); + g_assert(opts != NULL); + + parse_sandbox(NULL, opts, &error_abort); + + /* Running in a child process */ + ret = doit(); + + if (errnum != 0) { + g_assert(ret != 0); + g_assert(errno == errnum); + } else { + g_assert(ret == 0); + } + + _exit(0); + } else { + /* Running in main test process, spawning the child */ + g_test_trap_subprocess(NULL, 0, 0); + if (killed) { + g_test_trap_assert_failed(); + } else { + g_test_trap_assert_passed(); + } + } +} + + +static void test_seccomp_killed(const char *args, int (*doit)(void)) +{ + test_seccomp_helper(args, true, 0, doit); +} + +static void test_seccomp_errno(const char *args, int errnum, int (*doit)(void)) +{ + test_seccomp_helper(args, false, errnum, doit); +} + +static void test_seccomp_passed(const char *args, int (*doit)(void)) +{ + test_seccomp_helper(args, false, 0, doit); +} + +#ifdef SYS_fork +static int doit_sys_fork(void) +{ + int ret = syscall(SYS_fork); + if (ret < 0) { + return ret; + } + if (ret == 0) { + _exit(0); + } + return 0; +} + +static void test_seccomp_sys_fork_on_nospawn(void) +{ + test_seccomp_killed("on,spawn=deny", doit_sys_fork); +} + +static void test_seccomp_sys_fork_on(void) +{ + test_seccomp_passed("on", doit_sys_fork); +} + +static void test_seccomp_sys_fork_off(void) +{ + test_seccomp_passed("off", doit_sys_fork); +} +#endif + +static int doit_fork(void) +{ + int ret = fork(); + if (ret < 0) { + return ret; + } + if (ret == 0) { + _exit(0); + } + return 0; +} + +static void test_seccomp_fork_on_nospawn(void) +{ + test_seccomp_killed("on,spawn=deny", doit_fork); +} + +static void test_seccomp_fork_on(void) +{ + test_seccomp_passed("on", doit_fork); +} + +static void test_seccomp_fork_off(void) +{ + test_seccomp_passed("off", doit_fork); +} + +static void *noop(void *arg) +{ + return arg; +} + +static int doit_thread(void) +{ + pthread_t th; + int ret = pthread_create(&th, NULL, noop, NULL); + if (ret != 0) { + errno = ret; + return -1; + } else { + pthread_join(th, NULL); + return 0; + } +} + +static void test_seccomp_thread_on(void) +{ + test_seccomp_passed("on", doit_thread); +} + +static void test_seccomp_thread_on_nospawn(void) +{ + test_seccomp_passed("on,spawn=deny", doit_thread); +} + +static void test_seccomp_thread_off(void) +{ + test_seccomp_passed("off", doit_thread); +} + +static int doit_sched(void) +{ + struct sched_param param = { .sched_priority = 0 }; + return sched_setscheduler(getpid(), SCHED_OTHER, ¶m); +} + +static void test_seccomp_sched_on_nores(void) +{ + test_seccomp_errno("on,resourcecontrol=deny", EPERM, doit_sched); +} + +static void test_seccomp_sched_on(void) +{ + test_seccomp_passed("on", doit_sched); +} + +static void test_seccomp_sched_off(void) +{ + test_seccomp_passed("off", doit_sched); +} + +static bool can_play_with_seccomp(void) +{ + g_autofree char *status = NULL; + g_auto(GStrv) lines = NULL; + size_t i; + + if (!g_file_get_contents("/proc/self/status", &status, NULL, NULL)) { + return false; + } + + lines = g_strsplit(status, "\n", 0); + + for (i = 0; lines[i] != NULL; i++) { + if (g_str_has_prefix(lines[i], "Seccomp:")) { + /* + * "Seccomp: 1" or "Seccomp: 2" indicate we're already + * confined, probably as we're inside a container. In + * this case our tests might get unexpected results, + * so we can't run reliably + */ + if (!strchr(lines[i], '0')) { + return false; + } + + return true; + } + } + + /* Doesn't look like seccomp is enabled in the kernel */ + return false; +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + if (can_play_with_seccomp()) { +#ifdef SYS_fork + g_test_add_func("/softmmu/seccomp/sys-fork/on", + test_seccomp_sys_fork_on); + g_test_add_func("/softmmu/seccomp/sys-fork/on-nospawn", + test_seccomp_sys_fork_on_nospawn); + g_test_add_func("/softmmu/seccomp/sys-fork/off", + test_seccomp_sys_fork_off); +#endif + + g_test_add_func("/softmmu/seccomp/fork/on", + test_seccomp_fork_on); + g_test_add_func("/softmmu/seccomp/fork/on-nospawn", + test_seccomp_fork_on_nospawn); + g_test_add_func("/softmmu/seccomp/fork/off", + test_seccomp_fork_off); + + g_test_add_func("/softmmu/seccomp/thread/on", + test_seccomp_thread_on); + g_test_add_func("/softmmu/seccomp/thread/on-nospawn", + test_seccomp_thread_on_nospawn); + g_test_add_func("/softmmu/seccomp/thread/off", + test_seccomp_thread_off); + + if (doit_sched() == 0) { + /* + * musl doesn't impl sched_setscheduler, hence + * we check above if it works first + */ + g_test_add_func("/softmmu/seccomp/sched/on", + test_seccomp_sched_on); + g_test_add_func("/softmmu/seccomp/sched/on-nores", + test_seccomp_sched_on_nores); + g_test_add_func("/softmmu/seccomp/sched/off", + test_seccomp_sched_off); + } + } + return g_test_run(); +} diff --git a/tools/meson.build b/tools/meson.build index 3e5a0abfa2..46977af84f 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -1,25 +1,12 @@ -have_virtiofsd = (targetos == 'linux' and - have_tools and - seccomp.found() and - libcap_ng.found() and - 'CONFIG_VHOST_USER' in config_host) - -if get_option('virtiofsd').enabled() - if not have_virtiofsd - if targetos != 'linux' - error('virtiofsd requires Linux') - elif not seccomp.found() or not libcap_ng.found() - error('virtiofsd requires libcap-ng-devel and seccomp-devel') - elif 'CONFIG_VHOST_USER' not in config_host - error('virtiofsd needs vhost-user support') - else - # Disabled all the tools but virtiofsd. - have_virtiofsd = true - endif - endif -elif get_option('virtiofsd').disabled() or not have_system - have_virtiofsd = false -endif +have_virtiofsd = get_option('virtiofsd') \ + .require(targetos == 'linux', + error_message: 'virtiofsd requires Linux') \ + .require(seccomp.found() and libcap_ng.found(), + error_message: 'virtiofsd requires libcap-ng-devel and seccomp-devel') \ + .require('CONFIG_VHOST_USER' in config_host, + error_message: 'virtiofsd needs vhost-user-support') \ + .disable_auto_if(not have_tools and not have_system) \ + .allowed() if have_virtiofsd subdir('virtiofsd') diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h index 0c2665b977..bf46954dab 100644 --- a/tools/virtiofsd/fuse_common.h +++ b/tools/virtiofsd/fuse_common.h @@ -377,6 +377,11 @@ struct fuse_file_info { */ #define FUSE_CAP_SETXATTR_EXT (1 << 29) +/** + * Indicates that file server supports creating file security context + */ +#define FUSE_CAP_SECURITY_CTX (1ULL << 32) + /** * Ioctl flags * @@ -439,7 +444,7 @@ struct fuse_conn_info { /** * Capability flags that the kernel supports (read-only) */ - unsigned capable; + uint64_t capable; /** * Capability flags that the filesystem wants to enable. @@ -447,7 +452,7 @@ struct fuse_conn_info { * libfuse attempts to initialize this field with * reasonable default values before calling the init() handler. */ - unsigned want; + uint64_t want; /** * Maximum number of pending "background" requests. A diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h index 492e002181..a5572fa4ae 100644 --- a/tools/virtiofsd/fuse_i.h +++ b/tools/virtiofsd/fuse_i.h @@ -15,6 +15,12 @@ struct fv_VuDev; struct fv_QueueInfo; +struct fuse_security_context { + const char *name; + uint32_t ctxlen; + const void *ctx; +}; + struct fuse_req { struct fuse_session *se; uint64_t unique; @@ -35,6 +41,7 @@ struct fuse_req { } u; struct fuse_req *next; struct fuse_req *prev; + struct fuse_security_context secctx; }; struct fuse_notify_req { diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c index e4679c73ab..752928741d 100644 --- a/tools/virtiofsd/fuse_lowlevel.c +++ b/tools/virtiofsd/fuse_lowlevel.c @@ -886,11 +886,63 @@ static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, } } +static int parse_secctx_fill_req(fuse_req_t req, struct fuse_mbuf_iter *iter) +{ + struct fuse_secctx_header *fsecctx_header; + struct fuse_secctx *fsecctx; + const void *secctx; + const char *name; + + fsecctx_header = fuse_mbuf_iter_advance(iter, sizeof(*fsecctx_header)); + if (!fsecctx_header) { + return -EINVAL; + } + + /* + * As of now maximum of one security context is supported. It can + * change in future though. + */ + if (fsecctx_header->nr_secctx > 1) { + return -EINVAL; + } + + /* No security context sent. Maybe no LSM supports it */ + if (!fsecctx_header->nr_secctx) { + return 0; + } + + fsecctx = fuse_mbuf_iter_advance(iter, sizeof(*fsecctx)); + if (!fsecctx) { + return -EINVAL; + } + + /* struct fsecctx with zero sized context is not expected */ + if (!fsecctx->size) { + return -EINVAL; + } + name = fuse_mbuf_iter_advance_str(iter); + if (!name) { + return -EINVAL; + } + + secctx = fuse_mbuf_iter_advance(iter, fsecctx->size); + if (!secctx) { + return -EINVAL; + } + + req->secctx.name = name; + req->secctx.ctx = secctx; + req->secctx.ctxlen = fsecctx->size; + return 0; +} + static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, struct fuse_mbuf_iter *iter) { struct fuse_mknod_in *arg; const char *name; + bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; + int err; arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); name = fuse_mbuf_iter_advance_str(iter); @@ -901,6 +953,14 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, req->ctx.umask = arg->umask; + if (secctx_enabled) { + err = parse_secctx_fill_req(req, iter); + if (err) { + fuse_reply_err(req, -err); + return; + } + } + if (req->se->op.mknod) { req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev); } else { @@ -913,6 +973,8 @@ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, { struct fuse_mkdir_in *arg; const char *name; + bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; + int err; arg = fuse_mbuf_iter_advance(iter, sizeof(*arg)); name = fuse_mbuf_iter_advance_str(iter); @@ -923,6 +985,14 @@ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, req->ctx.umask = arg->umask; + if (secctx_enabled) { + err = parse_secctx_fill_req(req, iter); + if (err) { + fuse_reply_err(req, err); + return; + } + } + if (req->se->op.mkdir) { req->se->op.mkdir(req, nodeid, name, arg->mode); } else { @@ -969,12 +1039,22 @@ static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, { const char *name = fuse_mbuf_iter_advance_str(iter); const char *linkname = fuse_mbuf_iter_advance_str(iter); + bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; + int err; if (!name || !linkname) { fuse_reply_err(req, EINVAL); return; } + if (secctx_enabled) { + err = parse_secctx_fill_req(req, iter); + if (err) { + fuse_reply_err(req, err); + return; + } + } + if (req->se->op.symlink) { req->se->op.symlink(req, linkname, nodeid, name); } else { @@ -1048,6 +1128,8 @@ static void do_link(fuse_req_t req, fuse_ino_t nodeid, static void do_create(fuse_req_t req, fuse_ino_t nodeid, struct fuse_mbuf_iter *iter) { + bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX; + if (req->se->op.create) { struct fuse_create_in *arg; struct fuse_file_info fi; @@ -1060,6 +1142,15 @@ static void do_create(fuse_req_t req, fuse_ino_t nodeid, return; } + if (secctx_enabled) { + int err; + err = parse_secctx_fill_req(req, iter); + if (err) { + fuse_reply_err(req, err); + return; + } + } + memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; fi.kill_priv = arg->open_flags & FUSE_OPEN_KILL_SUIDGID; @@ -1876,15 +1967,30 @@ static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, } } +static void do_syncfs(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) +{ + if (req->se->op.syncfs) { + req->se->op.syncfs(req, nodeid); + } else { + fuse_reply_err(req, ENOSYS); + } +} + static void do_init(fuse_req_t req, fuse_ino_t nodeid, struct fuse_mbuf_iter *iter) { size_t compat_size = offsetof(struct fuse_init_in, max_readahead); + size_t compat2_size = offsetof(struct fuse_init_in, flags) + + sizeof(uint32_t); + /* Fuse structure extended with minor version 36 */ + size_t compat3_size = endof(struct fuse_init_in, unused); struct fuse_init_in *arg; struct fuse_init_out outarg; struct fuse_session *se = req->se; size_t bufsize = se->bufsize; size_t outargsize = sizeof(outarg); + uint64_t flags = 0; (void)nodeid; @@ -1897,15 +2003,29 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, /* ...and now consume the new fields. */ if (arg->major == 7 && arg->minor >= 6) { - if (!fuse_mbuf_iter_advance(iter, sizeof(*arg) - compat_size)) { + if (!fuse_mbuf_iter_advance(iter, compat2_size - compat_size)) { fuse_reply_err(req, EINVAL); return; } + flags |= arg->flags; + } + + /* + * fuse_init_in was extended again with minor version 36. Just read + * current known size of fuse_init so that future extension and + * header rebase does not cause breakage. + */ + if (sizeof(*arg) > compat2_size && (arg->flags & FUSE_INIT_EXT)) { + if (!fuse_mbuf_iter_advance(iter, compat3_size - compat2_size)) { + fuse_reply_err(req, EINVAL); + return; + } + flags |= (uint64_t) arg->flags2 << 32; } fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor); if (arg->major == 7 && arg->minor >= 6) { - fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags); + fuse_log(FUSE_LOG_DEBUG, "flags=0x%016llx\n", flags); fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n", arg->max_readahead); } se->conn.proto_major = arg->major; @@ -1933,70 +2053,73 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, if (arg->max_readahead < se->conn.max_readahead) { se->conn.max_readahead = arg->max_readahead; } - if (arg->flags & FUSE_ASYNC_READ) { + if (flags & FUSE_ASYNC_READ) { se->conn.capable |= FUSE_CAP_ASYNC_READ; } - if (arg->flags & FUSE_POSIX_LOCKS) { + if (flags & FUSE_POSIX_LOCKS) { se->conn.capable |= FUSE_CAP_POSIX_LOCKS; } - if (arg->flags & FUSE_ATOMIC_O_TRUNC) { + if (flags & FUSE_ATOMIC_O_TRUNC) { se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC; } - if (arg->flags & FUSE_EXPORT_SUPPORT) { + if (flags & FUSE_EXPORT_SUPPORT) { se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT; } - if (arg->flags & FUSE_DONT_MASK) { + if (flags & FUSE_DONT_MASK) { se->conn.capable |= FUSE_CAP_DONT_MASK; } - if (arg->flags & FUSE_FLOCK_LOCKS) { + if (flags & FUSE_FLOCK_LOCKS) { se->conn.capable |= FUSE_CAP_FLOCK_LOCKS; } - if (arg->flags & FUSE_AUTO_INVAL_DATA) { + if (flags & FUSE_AUTO_INVAL_DATA) { se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA; } - if (arg->flags & FUSE_DO_READDIRPLUS) { + if (flags & FUSE_DO_READDIRPLUS) { se->conn.capable |= FUSE_CAP_READDIRPLUS; } - if (arg->flags & FUSE_READDIRPLUS_AUTO) { + if (flags & FUSE_READDIRPLUS_AUTO) { se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO; } - if (arg->flags & FUSE_ASYNC_DIO) { + if (flags & FUSE_ASYNC_DIO) { se->conn.capable |= FUSE_CAP_ASYNC_DIO; } - if (arg->flags & FUSE_WRITEBACK_CACHE) { + if (flags & FUSE_WRITEBACK_CACHE) { se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE; } - if (arg->flags & FUSE_NO_OPEN_SUPPORT) { + if (flags & FUSE_NO_OPEN_SUPPORT) { se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT; } - if (arg->flags & FUSE_PARALLEL_DIROPS) { + if (flags & FUSE_PARALLEL_DIROPS) { se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS; } - if (arg->flags & FUSE_POSIX_ACL) { + if (flags & FUSE_POSIX_ACL) { se->conn.capable |= FUSE_CAP_POSIX_ACL; } - if (arg->flags & FUSE_HANDLE_KILLPRIV) { + if (flags & FUSE_HANDLE_KILLPRIV) { se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV; } - if (arg->flags & FUSE_NO_OPENDIR_SUPPORT) { + if (flags & FUSE_NO_OPENDIR_SUPPORT) { se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT; } - if (!(arg->flags & FUSE_MAX_PAGES)) { + if (!(flags & FUSE_MAX_PAGES)) { size_t max_bufsize = FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() + FUSE_BUFFER_HEADER_SIZE; if (bufsize > max_bufsize) { bufsize = max_bufsize; } } - if (arg->flags & FUSE_SUBMOUNTS) { + if (flags & FUSE_SUBMOUNTS) { se->conn.capable |= FUSE_CAP_SUBMOUNTS; } - if (arg->flags & FUSE_HANDLE_KILLPRIV_V2) { + if (flags & FUSE_HANDLE_KILLPRIV_V2) { se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV_V2; } - if (arg->flags & FUSE_SETXATTR_EXT) { + if (flags & FUSE_SETXATTR_EXT) { se->conn.capable |= FUSE_CAP_SETXATTR_EXT; } + if (flags & FUSE_SECURITY_CTX) { + se->conn.capable |= FUSE_CAP_SECURITY_CTX; + } #ifdef HAVE_SPLICE #ifdef HAVE_VMSPLICE se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; @@ -2051,7 +2174,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, if (se->conn.want & (~se->conn.capable)) { fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities " - "0x%x that are not supported by kernel, aborting.\n", + "0x%llx that are not supported by kernel, aborting.\n", se->conn.want & (~se->conn.capable)); fuse_reply_err(req, EPROTO); se->error = -EPROTO; @@ -2062,7 +2185,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) { se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE; } - if (arg->flags & FUSE_MAX_PAGES) { + if (flags & FUSE_MAX_PAGES) { outarg.flags |= FUSE_MAX_PAGES; outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1; } @@ -2136,8 +2259,14 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, outarg.flags |= FUSE_SETXATTR_EXT; } + if (se->conn.want & FUSE_CAP_SECURITY_CTX) { + /* bits 32..63 get shifted down 32 bits into the flags2 field */ + outarg.flags2 |= FUSE_SECURITY_CTX >> 32; + } + fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor); - fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags); + fuse_log(FUSE_LOG_DEBUG, " flags2=0x%08x flags=0x%08x\n", outarg.flags2, + outarg.flags); fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n", outarg.max_readahead); fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write); fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n", outarg.max_background); @@ -2280,6 +2409,7 @@ static struct { [FUSE_RENAME2] = { do_rename2, "RENAME2" }, [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" }, [FUSE_LSEEK] = { do_lseek, "LSEEK" }, + [FUSE_SYNCFS] = { do_syncfs, "SYNCFS" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h index c55c0ca2fc..b889dae4de 100644 --- a/tools/virtiofsd/fuse_lowlevel.h +++ b/tools/virtiofsd/fuse_lowlevel.h @@ -1226,6 +1226,19 @@ struct fuse_lowlevel_ops { */ void (*lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi); + + /** + * Synchronize file system content + * + * If this request is answered with an error code of ENOSYS, + * this is treated as success and future calls to syncfs() will + * succeed automatically without being sent to the filesystem + * process. + * + * @param req request handle + * @param ino the inode number + */ + void (*syncfs)(fuse_req_t req, fuse_ino_t ino); }; /** diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c index a8295d975a..e226fc590f 100644 --- a/tools/virtiofsd/helper.c +++ b/tools/virtiofsd/helper.c @@ -187,6 +187,7 @@ void fuse_cmdline_help(void) " default: no_allow_direct_io\n" " -o announce_submounts Announce sub-mount points to the guest\n" " -o posix_acl/no_posix_acl Enable/Disable posix_acl. (default: disabled)\n" + " -o security_label/no_security_label Enable/Disable security label. (default: disabled)\n" ); } diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index b3d0674f6d..dfa2fc250d 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -173,10 +173,15 @@ struct lo_data { /* An O_PATH file descriptor to /proc/self/fd/ */ int proc_self_fd; + /* An O_PATH file descriptor to /proc/self/task/ */ + int proc_self_task; int user_killpriv_v2, killpriv_v2; /* If set, virtiofsd is responsible for setting umask during creation */ bool change_umask; int user_posix_acl, posix_acl; + /* Keeps track if /proc//attr/fscreate should be used or not */ + bool use_fscreate; + int user_security_label; }; static const struct fuse_opt lo_opts[] = { @@ -211,6 +216,8 @@ static const struct fuse_opt lo_opts[] = { { "no_killpriv_v2", offsetof(struct lo_data, user_killpriv_v2), 0 }, { "posix_acl", offsetof(struct lo_data, user_posix_acl), 1 }, { "no_posix_acl", offsetof(struct lo_data, user_posix_acl), 0 }, + { "security_label", offsetof(struct lo_data, user_security_label), 1 }, + { "no_security_label", offsetof(struct lo_data, user_security_label), 0 }, FUSE_OPT_END }; static bool use_syslog = false; @@ -230,6 +237,11 @@ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st, static int xattr_map_client(const struct lo_data *lo, const char *client_name, char **out_name); +#define FCHDIR_NOFAIL(fd) do { \ + int fchdir_res = fchdir(fd); \ + assert(fchdir_res == 0); \ + } while (0) + static bool is_dot_or_dotdot(const char *name) { return name[0] == '.' && @@ -256,6 +268,70 @@ static struct lo_data *lo_data(fuse_req_t req) return (struct lo_data *)fuse_req_userdata(req); } +/* + * Tries to figure out if /proc//attr/fscreate is usable or not. With + * selinux=0, read from fscreate returns -EINVAL. + * + * TODO: Link with libselinux and use is_selinux_enabled() instead down + * the line. It probably will be more reliable indicator. + */ +static bool is_fscreate_usable(struct lo_data *lo) +{ + char procname[64]; + int fscreate_fd; + size_t bytes_read; + + sprintf(procname, "%ld/attr/fscreate", syscall(SYS_gettid)); + fscreate_fd = openat(lo->proc_self_task, procname, O_RDWR); + if (fscreate_fd == -1) { + return false; + } + + bytes_read = read(fscreate_fd, procname, 64); + close(fscreate_fd); + if (bytes_read == -1) { + return false; + } + return true; +} + +/* Helpers to set/reset fscreate */ +static int open_set_proc_fscreate(struct lo_data *lo, const void *ctx, + size_t ctxlen, int *fd) +{ + char procname[64]; + int fscreate_fd, err = 0; + size_t written; + + sprintf(procname, "%ld/attr/fscreate", syscall(SYS_gettid)); + fscreate_fd = openat(lo->proc_self_task, procname, O_WRONLY); + err = fscreate_fd == -1 ? errno : 0; + if (err) { + return err; + } + + written = write(fscreate_fd, ctx, ctxlen); + err = written == -1 ? errno : 0; + if (err) { + goto out; + } + + *fd = fscreate_fd; + return 0; +out: + close(fscreate_fd); + return err; +} + +static void close_reset_proc_fscreate(int fd) +{ + if ((write(fd, NULL, 0)) == -1) { + fuse_log(FUSE_LOG_WARNING, "Failed to reset fscreate. err=%d\n", errno); + } + close(fd); + return; +} + /* * Load capng's state from our saved state if the current thread * hadn't previously been loaded. @@ -735,6 +811,17 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn) fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling posix_acl\n"); conn->want &= ~FUSE_CAP_POSIX_ACL; } + + if (lo->user_security_label == 1) { + if (!(conn->capable & FUSE_CAP_SECURITY_CTX)) { + fuse_log(FUSE_LOG_ERR, "lo_init: Can not enable security label." + " kernel does not support FUSE_SECURITY_CTX capability.\n"); + } + conn->want |= FUSE_CAP_SECURITY_CTX; + } else { + fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling security label\n"); + conn->want &= ~FUSE_CAP_SECURITY_CTX; + } } static void lo_getattr(fuse_req_t req, fuse_ino_t ino, @@ -1284,16 +1371,103 @@ static void lo_restore_cred_gain_cap(struct lo_cred *old, bool restore_umask, } } +static int do_mknod_symlink_secctx(fuse_req_t req, struct lo_inode *dir, + const char *name, const char *secctx_name) +{ + int path_fd, err; + char procname[64]; + struct lo_data *lo = lo_data(req); + + if (!req->secctx.ctxlen) { + return 0; + } + + /* Open newly created element with O_PATH */ + path_fd = openat(dir->fd, name, O_PATH | O_NOFOLLOW); + err = path_fd == -1 ? errno : 0; + if (err) { + return err; + } + sprintf(procname, "%i", path_fd); + FCHDIR_NOFAIL(lo->proc_self_fd); + /* Set security context. This is not atomic w.r.t file creation */ + err = setxattr(procname, secctx_name, req->secctx.ctx, req->secctx.ctxlen, + 0); + if (err) { + err = errno; + } + FCHDIR_NOFAIL(lo->root.fd); + close(path_fd); + return err; +} + +static int do_mknod_symlink(fuse_req_t req, struct lo_inode *dir, + const char *name, mode_t mode, dev_t rdev, + const char *link) +{ + int err, fscreate_fd = -1; + const char *secctx_name = req->secctx.name; + struct lo_cred old = {}; + struct lo_data *lo = lo_data(req); + char *mapped_name = NULL; + bool secctx_enabled = req->secctx.ctxlen; + bool do_fscreate = false; + + if (secctx_enabled && lo->xattrmap) { + err = xattr_map_client(lo, req->secctx.name, &mapped_name); + if (err < 0) { + return -err; + } + secctx_name = mapped_name; + } + + /* + * If security xattr has not been remapped and selinux is enabled on + * host, set fscreate and no need to do a setxattr() after file creation + */ + if (secctx_enabled && !mapped_name && lo->use_fscreate) { + do_fscreate = true; + err = open_set_proc_fscreate(lo, req->secctx.ctx, req->secctx.ctxlen, + &fscreate_fd); + if (err) { + goto out; + } + } + + err = lo_change_cred(req, &old, lo->change_umask && !S_ISLNK(mode)); + if (err) { + goto out; + } + + err = mknod_wrapper(dir->fd, name, link, mode, rdev); + err = err == -1 ? errno : 0; + lo_restore_cred(&old, lo->change_umask && !S_ISLNK(mode)); + if (err) { + goto out; + } + + if (!do_fscreate) { + err = do_mknod_symlink_secctx(req, dir, name, secctx_name); + if (err) { + unlinkat(dir->fd, name, S_ISDIR(mode) ? AT_REMOVEDIR : 0); + } + } +out: + if (fscreate_fd != -1) { + close_reset_proc_fscreate(fscreate_fd); + } + g_free(mapped_name); + return err; +} + static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev, const char *link) { - int res; int saverr; struct lo_data *lo = lo_data(req); struct lo_inode *dir; struct fuse_entry_param e; - struct lo_cred old = {}; if (is_empty(name)) { fuse_reply_err(req, ENOENT); @@ -1311,21 +1485,11 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent, return; } - saverr = lo_change_cred(req, &old, lo->change_umask && !S_ISLNK(mode)); + saverr = do_mknod_symlink(req, dir, name, mode, rdev, link); if (saverr) { goto out; } - res = mknod_wrapper(dir->fd, name, link, mode, rdev); - - saverr = errno; - - lo_restore_cred(&old, lo->change_umask && !S_ISLNK(mode)); - - if (res == -1) { - goto out; - } - saverr = lo_do_lookup(req, parent, name, &e, NULL); if (saverr) { goto out; @@ -2001,6 +2165,190 @@ static int lo_do_open(struct lo_data *lo, struct lo_inode *inode, return 0; } +static int do_create_nosecctx(fuse_req_t req, struct lo_inode *parent_inode, + const char *name, mode_t mode, + struct fuse_file_info *fi, int *open_fd, + bool tmpfile) +{ + int err, fd; + struct lo_cred old = {}; + struct lo_data *lo = lo_data(req); + int flags; + + if (tmpfile) { + flags = fi->flags | O_TMPFILE; + /* + * Don't use O_EXCL as we want to link file later. Also reset O_CREAT + * otherwise openat() returns -EINVAL. + */ + flags &= ~(O_CREAT | O_EXCL); + + /* O_TMPFILE needs either O_RDWR or O_WRONLY */ + if ((flags & O_ACCMODE) == O_RDONLY) { + flags |= O_RDWR; + } + } else { + flags = fi->flags | O_CREAT | O_EXCL; + } + + err = lo_change_cred(req, &old, lo->change_umask); + if (err) { + return err; + } + + /* Try to create a new file but don't open existing files */ + fd = openat(parent_inode->fd, name, flags, mode); + err = fd == -1 ? errno : 0; + lo_restore_cred(&old, lo->change_umask); + if (!err) { + *open_fd = fd; + } + return err; +} + +static int do_create_secctx_fscreate(fuse_req_t req, + struct lo_inode *parent_inode, + const char *name, mode_t mode, + struct fuse_file_info *fi, int *open_fd) +{ + int err = 0, fd = -1, fscreate_fd = -1; + struct lo_data *lo = lo_data(req); + + err = open_set_proc_fscreate(lo, req->secctx.ctx, req->secctx.ctxlen, + &fscreate_fd); + if (err) { + return err; + } + + err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd, false); + + close_reset_proc_fscreate(fscreate_fd); + if (!err) { + *open_fd = fd; + } + return err; +} + +static int do_create_secctx_tmpfile(fuse_req_t req, + struct lo_inode *parent_inode, + const char *name, mode_t mode, + struct fuse_file_info *fi, + const char *secctx_name, int *open_fd) +{ + int err, fd = -1; + struct lo_data *lo = lo_data(req); + char procname[64]; + + err = do_create_nosecctx(req, parent_inode, ".", mode, fi, &fd, true); + if (err) { + return err; + } + + err = fsetxattr(fd, secctx_name, req->secctx.ctx, req->secctx.ctxlen, 0); + if (err) { + err = errno; + goto out; + } + + /* Security context set on file. Link it in place */ + sprintf(procname, "%d", fd); + FCHDIR_NOFAIL(lo->proc_self_fd); + err = linkat(AT_FDCWD, procname, parent_inode->fd, name, + AT_SYMLINK_FOLLOW); + err = err == -1 ? errno : 0; + FCHDIR_NOFAIL(lo->root.fd); + +out: + if (!err) { + *open_fd = fd; + } else if (fd != -1) { + close(fd); + } + return err; +} + +static int do_create_secctx_noatomic(fuse_req_t req, + struct lo_inode *parent_inode, + const char *name, mode_t mode, + struct fuse_file_info *fi, + const char *secctx_name, int *open_fd) +{ + int err = 0, fd = -1; + + err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd, false); + if (err) { + goto out; + } + + /* Set security context. This is not atomic w.r.t file creation */ + err = fsetxattr(fd, secctx_name, req->secctx.ctx, req->secctx.ctxlen, 0); + err = err == -1 ? errno : 0; +out: + if (!err) { + *open_fd = fd; + } else { + if (fd != -1) { + close(fd); + unlinkat(parent_inode->fd, name, 0); + } + } + return err; +} + +static int do_lo_create(fuse_req_t req, struct lo_inode *parent_inode, + const char *name, mode_t mode, + struct fuse_file_info *fi, int *open_fd) +{ + struct lo_data *lo = lo_data(req); + char *mapped_name = NULL; + int err; + const char *ctxname = req->secctx.name; + bool secctx_enabled = req->secctx.ctxlen; + + if (secctx_enabled && lo->xattrmap) { + err = xattr_map_client(lo, req->secctx.name, &mapped_name); + if (err < 0) { + return -err; + } + + ctxname = mapped_name; + } + + if (secctx_enabled) { + /* + * If security.selinux has not been remapped and selinux is enabled, + * use fscreate to set context before file creation. If not, use + * tmpfile method for regular files. Otherwise fallback to + * non-atomic method of file creation and xattr settting. + */ + if (!mapped_name && lo->use_fscreate) { + err = do_create_secctx_fscreate(req, parent_inode, name, mode, fi, + open_fd); + goto out; + } else if (S_ISREG(mode)) { + err = do_create_secctx_tmpfile(req, parent_inode, name, mode, fi, + ctxname, open_fd); + /* + * If filesystem does not support O_TMPFILE, fallback to non-atomic + * method. + */ + if (!err || err != EOPNOTSUPP) { + goto out; + } + } + + err = do_create_secctx_noatomic(req, parent_inode, name, mode, fi, + ctxname, open_fd); + } else { + err = do_create_nosecctx(req, parent_inode, name, mode, fi, open_fd, + false); + } + +out: + g_free(mapped_name); + return err; +} + static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) { @@ -2010,7 +2358,6 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, struct lo_inode *inode = NULL; struct fuse_entry_param e; int err; - struct lo_cred old = {}; fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)" " kill_priv=%d\n", parent, name, fi->kill_priv); @@ -2026,18 +2373,9 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, return; } - err = lo_change_cred(req, &old, lo->change_umask); - if (err) { - goto out; - } - update_open_flags(lo->writeback, lo->allow_direct_io, fi); - /* Try to create a new file but don't open existing files */ - fd = openat(parent_inode->fd, name, fi->flags | O_CREAT | O_EXCL, mode); - err = fd == -1 ? errno : 0; - - lo_restore_cred(&old, lo->change_umask); + err = do_lo_create(req, parent_inode, name, mode, fi, &fd); /* Ignore the error if file exists and O_EXCL was not given */ if (err && (err != EEXIST || (fi->flags & O_EXCL))) { @@ -2467,6 +2805,15 @@ static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int res; (void)ino; + if (!(op & LOCK_NB)) { + /* + * Blocking flock can deadlock as there is only one thread + * serving the queue. + */ + fuse_reply_err(req, EOPNOTSUPP); + return; + } + res = flock(lo_fi_fd(req, fi), op); fuse_reply_err(req, res == -1 ? errno : 0); @@ -2842,11 +3189,6 @@ static int xattr_map_server(const struct lo_data *lo, const char *server_name, return -ENODATA; } -#define FCHDIR_NOFAIL(fd) do { \ - int fchdir_res = fchdir(fd); \ - assert(fchdir_res == 0); \ - } while (0) - static bool block_xattr(struct lo_data *lo, const char *name) { /* @@ -3357,6 +3699,49 @@ static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, } } +static int lo_do_syncfs(struct lo_data *lo, struct lo_inode *inode) +{ + int fd, ret = 0; + + fuse_log(FUSE_LOG_DEBUG, "lo_do_syncfs(ino=%" PRIu64 ")\n", + inode->fuse_ino); + + fd = lo_inode_open(lo, inode, O_RDONLY); + if (fd < 0) { + return -fd; + } + + if (syncfs(fd) < 0) { + ret = errno; + } + + close(fd); + return ret; +} + +static void lo_syncfs(fuse_req_t req, fuse_ino_t ino) +{ + struct lo_data *lo = lo_data(req); + struct lo_inode *inode = lo_inode(req, ino); + int err; + + if (!inode) { + fuse_reply_err(req, EBADF); + return; + } + + err = lo_do_syncfs(lo, inode); + lo_inode_put(lo, &inode); + + /* + * If submounts aren't announced, the client only sends a request to + * sync the root inode. TODO: Track submounts internally and iterate + * over them as well. + */ + + fuse_reply_err(req, err); +} + static void lo_destroy(void *userdata) { struct lo_data *lo = (struct lo_data *)userdata; @@ -3417,6 +3802,7 @@ static struct fuse_lowlevel_ops lo_oper = { .copy_file_range = lo_copy_file_range, #endif .lseek = lo_lseek, + .syncfs = lo_syncfs, .destroy = lo_destroy, }; @@ -3508,6 +3894,15 @@ static void setup_namespaces(struct lo_data *lo, struct fuse_session *se) exit(1); } + /* Get the /proc/self/task descriptor */ + lo->proc_self_task = open("/proc/self/task/", O_PATH); + if (lo->proc_self_task == -1) { + fuse_log(FUSE_LOG_ERR, "open(/proc/self/task, O_PATH): %m\n"); + exit(1); + } + + lo->use_fscreate = is_fscreate_usable(lo); + /* * We only need /proc/self/fd. Prevent ".." from accessing parent * directories of /proc/self/fd by bind-mounting it over /proc. Since / was @@ -3724,6 +4119,14 @@ static void setup_chroot(struct lo_data *lo) exit(1); } + lo->proc_self_task = open("/proc/self/task", O_PATH); + if (lo->proc_self_fd == -1) { + fuse_log(FUSE_LOG_ERR, "open(\"/proc/self/task\", O_PATH): %m\n"); + exit(1); + } + + lo->use_fscreate = is_fscreate_usable(lo); + /* * Make the shared directory the file system root so that FUSE_OPEN * (lo_open()) cannot escape the shared directory by opening a symlink. @@ -3909,6 +4312,10 @@ static void fuse_lo_data_cleanup(struct lo_data *lo) close(lo->proc_self_fd); } + if (lo->proc_self_task >= 0) { + close(lo->proc_self_task); + } + if (lo->root.fd >= 0) { close(lo->root.fd); } @@ -3936,8 +4343,10 @@ int main(int argc, char *argv[]) .posix_lock = 0, .allow_direct_io = 0, .proc_self_fd = -1, + .proc_self_task = -1, .user_killpriv_v2 = -1, .user_posix_acl = -1, + .user_security_label = -1, }; struct lo_map_elem *root_elem; struct lo_map_elem *reserve_elem; diff --git a/tools/virtiofsd/passthrough_seccomp.c b/tools/virtiofsd/passthrough_seccomp.c index 2bc0127b69..888295c073 100644 --- a/tools/virtiofsd/passthrough_seccomp.c +++ b/tools/virtiofsd/passthrough_seccomp.c @@ -111,6 +111,7 @@ static const int syscall_allowlist[] = { SCMP_SYS(set_robust_list), SCMP_SYS(setxattr), SCMP_SYS(symlinkat), + SCMP_SYS(syncfs), SCMP_SYS(time), /* Rarely needed, except on static builds */ SCMP_SYS(tgkill), SCMP_SYS(unlinkat), diff --git a/ui/cocoa.m b/ui/cocoa.m index ac18e14ce0..a8f1cdaf92 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -100,7 +100,6 @@ static int gArgc; static char **gArgv; static bool stretch_video; static NSTextField *pauseLabel; -static NSArray * supportedImageFileTypes; static QemuSemaphore display_init_sem; static QemuSemaphore app_started_sem; @@ -1168,10 +1167,6 @@ QemuCocoaView *cocoaView; [pauseLabel setTextColor: [NSColor blackColor]]; [pauseLabel sizeToFit]; - // set the supported image file types that can be opened - supportedImageFileTypes = [NSArray arrayWithObjects: @"img", @"iso", @"dmg", - @"qcow", @"qcow2", @"cloop", @"vmdk", @"cdr", - @"toast", nil]; [self make_about_window]; } return self; @@ -1414,7 +1409,6 @@ QemuCocoaView *cocoaView; openPanel = [NSOpenPanel openPanel]; [openPanel setCanChooseFiles: YES]; [openPanel setAllowsMultipleSelection: NO]; - [openPanel setAllowedFileTypes: supportedImageFileTypes]; if([openPanel runModal] == NSModalResponseOK) { NSString * file = [[[openPanel URLs] objectAtIndex: 0] path]; if(file == nil) { @@ -1680,7 +1674,9 @@ static void create_initial_menus(void) /* Returns a name for a given console */ static NSString * getConsoleName(QemuConsole * console) { - return [NSString stringWithFormat: @"%s", qemu_console_get_label(console)]; + g_autofree char *label = qemu_console_get_label(console); + + return [NSString stringWithUTF8String:label]; } /* Add an entry to the View menu for each console */ @@ -1715,11 +1711,6 @@ static void addRemovableDevicesMenuItems(void) currentDevice = qmp_query_block(NULL); pointerToFree = currentDevice; - if(currentDevice == NULL) { - NSBeep(); - QEMU_Alert(@"Failed to query for block devices!"); - return; - } menu = [[[NSApp mainMenu] itemWithTitle:@"Machine"] submenu]; diff --git a/util/atomic64.c b/util/atomic64.c index 93037d5b11..22983a970f 100644 --- a/util/atomic64.c +++ b/util/atomic64.c @@ -7,6 +7,7 @@ #include "qemu/osdep.h" #include "qemu/atomic.h" #include "qemu/thread.h" +#include "qemu/cacheinfo.h" #ifdef CONFIG_ATOMIC64 #error This file must only be compiled if !CONFIG_ATOMIC64 diff --git a/util/cacheflush.c b/util/cacheflush.c index 933355b0c9..4b57186d89 100644 --- a/util/cacheflush.c +++ b/util/cacheflush.c @@ -7,6 +7,7 @@ #include "qemu/osdep.h" #include "qemu/cacheflush.h" +#include "qemu/cacheinfo.h" #include "qemu/bitops.h" diff --git a/util/cacheinfo.c b/util/cacheinfo.c index b182f0b693..ab1644d490 100644 --- a/util/cacheinfo.c +++ b/util/cacheinfo.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qemu/host-utils.h" #include "qemu/atomic.h" +#include "qemu/cacheinfo.h" int qemu_icache_linesize = 0; int qemu_icache_linesize_log; diff --git a/util/meson.build b/util/meson.build index c9a9cc1cf5..3736988b9f 100644 --- a/util/meson.build +++ b/util/meson.build @@ -35,7 +35,9 @@ util_ss.add(files('crc32c.c')) util_ss.add(files('uuid.c')) util_ss.add(files('getauxval.c')) util_ss.add(files('rcu.c')) -util_ss.add(when: 'CONFIG_MEMBARRIER', if_true: files('sys_membarrier.c')) +if have_membarrier + util_ss.add(files('sys_membarrier.c')) +endif util_ss.add(files('log.c')) util_ss.add(files('pagesize.c')) util_ss.add(files('qdist.c')) diff --git a/util/osdep.c b/util/osdep.c index 42a0a4986a..723cdcb004 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -33,10 +33,14 @@ extern int madvise(char *, size_t, int); #endif +#include #include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/sockets.h" #include "qemu/error-report.h" +#include "qemu/madvise.h" +#include "qemu/mprotect.h" +#include "qemu/hw-version.h" #include "monitor/monitor.h" static bool fips_enabled = false; @@ -615,3 +619,23 @@ writev(int fd, const struct iovec *iov, int iov_cnt) return readv_writev(fd, iov, iov_cnt, true); } #endif + +struct dirent * +qemu_dirent_dup(struct dirent *dent) +{ + size_t sz = 0; +#if defined _DIRENT_HAVE_D_RECLEN + /* Avoid use of strlen() if platform supports d_reclen. */ + sz = dent->d_reclen; +#endif + /* + * Test sz for zero even if d_reclen is available + * because some drivers may set d_reclen to zero. + */ + if (sz == 0) { + /* Fallback to the most portable way. */ + sz = offsetof(struct dirent, d_name) + + strlen(dent->d_name) + 1; + } + return g_memdup(dent, sz); +} diff --git a/util/oslib-posix.c b/util/oslib-posix.c index ac0dbc2adc..f2be7321c5 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -36,6 +36,7 @@ #include "trace.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "qemu/madvise.h" #include "qemu/sockets.h" #include "qemu/thread.h" #include