diff --git a/configure b/configure index b0b1a1cc25..877bf3d76a 100755 --- a/configure +++ b/configure @@ -142,11 +142,11 @@ lines: ${BASH_LINENO[*]}" } do_cc() { - do_compiler "$cc" "$@" + do_compiler "$cc" $CPU_CFLAGS "$@" } do_cxx() { - do_compiler "$cxx" "$@" + do_compiler "$cxx" $CPU_CFLAGS "$@" } # Append $2 to the variable named $1, with space separation @@ -1688,7 +1688,6 @@ esac eval "cross_cc_${cpu}=\$cc" cross_cc_vars="$cross_cc_vars cross_cc_${cpu}" -QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS" # For user-mode emulation the host arch has to be one we explicitly # support, even if we're using TCI. @@ -1995,7 +1994,7 @@ python_version=$($python -c 'import sys; print("%d.%d.%d" % (sys.version_info[0] python="$python -B" if test -z "$meson"; then - if test "$explicit_python" = no && has meson && version_ge "$(meson --version)" 0.55.3; then + if test "$explicit_python" = no && has meson && version_ge "$(meson --version)" 0.59.2; then meson=meson elif test $git_submodules_action != 'ignore' ; then meson=git @@ -5114,9 +5113,9 @@ if test "$skip_meson" = no; then echo "c_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross echo "cpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross echo "[binaries]" >> $cross - echo "c = [$(meson_quote $cc)]" >> $cross - test -n "$cxx" && echo "cpp = [$(meson_quote $cxx)]" >> $cross - test -n "$objcc" && echo "objc = [$(meson_quote $objcc)]" >> $cross + echo "c = [$(meson_quote $cc $CPU_CFLAGS)]" >> $cross + test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross + test -n "$objcc" && echo "objc = [$(meson_quote $objcc $CPU_CFLAGS)]" >> $cross echo "ar = [$(meson_quote $ar)]" >> $cross echo "nm = [$(meson_quote $nm)]" >> $cross echo "pkgconfig = [$(meson_quote $pkg_config_exe)]" >> $cross @@ -5164,10 +5163,6 @@ if test "$skip_meson" = no; then mv $cross config-meson.cross rm -rf meson-private meson-info meson-logs - unset staticpic - if ! version_ge "$($meson --version)" 0.56.0; then - staticpic=$(if test "$pie" = yes; then echo true; else echo false; fi) - fi NINJA=$ninja $meson setup \ --prefix "$prefix" \ --libdir "$libdir" \ @@ -5187,7 +5182,6 @@ if test "$skip_meson" = no; then -Dwerror=$(if test "$werror" = yes; then echo true; else echo false; fi) \ -Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \ -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ - ${staticpic:+-Db_staticpic=$staticpic} \ -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ -Db_lto=$lto -Dcfi=$cfi -Dcfi_debug=$cfi_debug \ -Dmalloc=$malloc -Dmalloc_trim=$malloc_trim -Dsparse=$sparse \ @@ -5223,6 +5217,7 @@ else perl -i -ne ' s/^gettext = true$/gettext = auto/; s/^gettext = false$/gettext = disabled/; + /^b_staticpic/ && next; print;' meson-private/cmd_line.txt fi fi diff --git a/docs/meson.build b/docs/meson.build index cffe1ecf1d..be4dc30f39 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -37,14 +37,14 @@ endif if build_docs SPHINX_ARGS += ['-Dversion=' + meson.project_version(), '-Drelease=' + config_host['PKGVERSION']] - sphinx_extn_depends = [ meson.source_root() / 'docs/sphinx/depfile.py', - meson.source_root() / 'docs/sphinx/hxtool.py', - meson.source_root() / 'docs/sphinx/kerneldoc.py', - meson.source_root() / 'docs/sphinx/kernellog.py', - meson.source_root() / 'docs/sphinx/qapidoc.py', - meson.source_root() / 'docs/sphinx/qmp_lexer.py', + sphinx_extn_depends = [ meson.current_source_dir() / 'sphinx/depfile.py', + meson.current_source_dir() / 'sphinx/hxtool.py', + meson.current_source_dir() / 'sphinx/kerneldoc.py', + meson.current_source_dir() / 'sphinx/kernellog.py', + meson.current_source_dir() / 'sphinx/qapidoc.py', + meson.current_source_dir() / 'sphinx/qmp_lexer.py', qapi_gen_depends ] - sphinx_template_files = [ meson.source_root() / 'docs/_templates/footer.html' ] + sphinx_template_files = [ meson.project_source_root() / 'docs/_templates/footer.html' ] have_ga = have_tools and config_host.has_key('CONFIG_GUEST_AGENT') diff --git a/docs/system/i386/kvm-pv.rst b/docs/system/i386/kvm-pv.rst new file mode 100644 index 0000000000..1e5a9923ef --- /dev/null +++ b/docs/system/i386/kvm-pv.rst @@ -0,0 +1,100 @@ +Paravirtualized KVM features +============================ + +Description +----------- + +In some cases when implementing hardware interfaces in software is slow, ``KVM`` +implements its own paravirtualized interfaces. + +Setup +----- + +Paravirtualized ``KVM`` features are represented as CPU flags. The following +features are enabled by default for any CPU model when ``KVM`` acceleration is +enabled: + +- ``kvmclock`` +- ``kvm-nopiodelay`` +- ``kvm-asyncpf`` +- ``kvm-steal-time`` +- ``kvm-pv-eoi`` +- ``kvmclock-stable-bit`` + +``kvm-msi-ext-dest-id`` feature is enabled by default in x2apic mode with split +irqchip (e.g. "-machine ...,kernel-irqchip=split -cpu ...,x2apic"). + +Note: when CPU model ``host`` is used, QEMU passes through all supported +paravirtualized ``KVM`` features to the guest. + +Existing features +----------------- + +``kvmclock`` + Expose a ``KVM`` specific paravirtualized clocksource to the guest. Supported + since Linux v2.6.26. + +``kvm-nopiodelay`` + The guest doesn't need to perform delays on PIO operations. Supported since + Linux v2.6.26. + +``kvm-mmu`` + This feature is deprecated. + +``kvm-asyncpf`` + Enable asynchronous page fault mechanism. Supported since Linux v2.6.38. + Note: since Linux v5.10 the feature is deprecated and not enabled by ``KVM``. + Use ``kvm-asyncpf-int`` instead. + +``kvm-steal-time`` + Enable stolen (when guest vCPU is not running) time accounting. Supported + since Linux v3.1. + +``kvm-pv-eoi`` + Enable paravirtualized end-of-interrupt signaling. Supported since Linux + v3.10. + +``kvm-pv-unhalt`` + Enable paravirtualized spinlocks support. Supported since Linux v3.12. + +``kvm-pv-tlb-flush`` + Enable paravirtualized TLB flush mechanism. Supported since Linux v4.16. + +``kvm-pv-ipi`` + Enable paravirtualized IPI mechanism. Supported since Linux v4.19. + +``kvm-poll-control`` + Enable host-side polling on HLT control from the guest. Supported since Linux + v5.10. + +``kvm-pv-sched-yield`` + Enable paravirtualized sched yield feature. Supported since Linux v5.10. + +``kvm-asyncpf-int`` + Enable interrupt based asynchronous page fault mechanism. Supported since Linux + v5.10. + +``kvm-msi-ext-dest-id`` + Support 'Extended Destination ID' for external interrupts. The feature allows + to use up to 32768 CPUs without IRQ remapping (but other limits may apply making + the number of supported vCPUs for a given configuration lower). Supported since + Linux v5.10. + +``kvmclock-stable-bit`` + Tell the guest that guest visible TSC value can be fully trusted for kvmclock + computations and no warps are expected. Supported since Linux v2.6.35. + +Supplementary features +---------------------- + +``kvm-pv-enforce-cpuid`` + Limit the supported paravirtualized feature set to the exposed features only. + Note, by default, ``KVM`` allows the guest to use all currently supported + paravirtualized features even when they were not announced in guest visible + CPUIDs. Supported since Linux v5.10. + + +Useful links +------------ + +Please refer to Documentation/virt/kvm in Linux for additional details. diff --git a/docs/system/target-i386.rst b/docs/system/target-i386.rst index 6a86d63863..4daa53c35d 100644 --- a/docs/system/target-i386.rst +++ b/docs/system/target-i386.rst @@ -26,6 +26,7 @@ Architectural features :maxdepth: 1 i386/cpu + i386/kvm-pv i386/sgx .. _pcsys_005freq: diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 41ef9a84a9..0c7c054e3a 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -47,6 +47,7 @@ #include "hw/i386/fw_cfg.h" #include "hw/intc/i8259.h" #include "hw/rtc/mc146818rtc.h" +#include "target/i386/sev_i386.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/irq.h" @@ -780,6 +781,7 @@ void x86_load_linux(X86MachineState *x86ms, const char *initrd_filename = machine->initrd_filename; const char *dtb_filename = machine->dtb; const char *kernel_cmdline = machine->kernel_cmdline; + SevKernelLoaderContext sev_load_ctx = {}; /* Align to 16 bytes as a paranoia measure */ cmdline_size = (strlen(kernel_cmdline) + 16) & ~15; @@ -926,6 +928,8 @@ void x86_load_linux(X86MachineState *x86ms, fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + sev_load_ctx.cmdline_data = (char *)kernel_cmdline; + sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1; if (protocol >= 0x202) { stl_p(header + 0x228, cmdline_addr); @@ -1007,6 +1011,8 @@ void x86_load_linux(X86MachineState *x86ms, fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size); + sev_load_ctx.initrd_data = initrd_data; + sev_load_ctx.initrd_size = initrd_size; stl_p(header + 0x218, initrd_addr); stl_p(header + 0x21c, initrd_size); @@ -1065,15 +1071,32 @@ void x86_load_linux(X86MachineState *x86ms, load_image_size(dtb_filename, setup_data->data, dtb_size); } - memcpy(setup, header, MIN(sizeof(header), setup_size)); + /* + * If we're starting an encrypted VM, it will be OVMF based, which uses the + * efi stub for booting and doesn't require any values to be placed in the + * kernel header. We therefore don't update the header so the hash of the + * kernel on the other side of the fw_cfg interface matches the hash of the + * file the user passed in. + */ + if (!sev_enabled()) { + memcpy(setup, header, MIN(sizeof(header), setup_size)); + } fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); + sev_load_ctx.kernel_data = (char *)kernel; + sev_load_ctx.kernel_size = kernel_size; fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size); + sev_load_ctx.setup_data = (char *)setup; + sev_load_ctx.setup_size = setup_size; + + if (sev_enabled()) { + sev_add_kernel_loader_hashes(&sev_load_ctx, &error_fatal); + } option_rom[nb_option_roms].bootindex = 0; option_rom[nb_option_roms].name = "linuxboot.bin"; diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index 1b9acaf1d3..cec247b5ee 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -38,6 +38,171 @@ #include "qemu/timer.h" #include "qom/object.h" +#if defined(__APPLE__) && defined(__MACH__) +#include + +enum { + kSMCSuccess = 0x00, + kSMCKeyNotFound = 0x84 +}; + +enum { + kSMCUserClientOpen = 0x00, + kSMCUserClientClose = 0x01, + kSMCHandleYPCEvent = 0x02, + kSMCReadKey = 0x05, + kSMCGetKeyInfo = 0x09 +}; + +typedef struct SMCVersion { + uint8_t major; + uint8_t minor; + uint8_t build; + uint8_t reserved; + uint16_t release; +} SMCVersion; + +typedef struct SMCPLimitData { + uint16_t version; + uint16_t length; + uint32_t cpuPLimit; + uint32_t gpuPLimit; + uint32_t memPLimit; +} SMCPLimitData; + +typedef struct SMCKeyInfoData { + IOByteCount dataSize; + uint32_t dataType; + uint8_t dataAttributes; +} SMCKeyInfoData; + +typedef struct { + uint32_t key; + SMCVersion vers; + SMCPLimitData pLimitData; + SMCKeyInfoData keyInfo; + uint8_t result; + uint8_t status; + uint8_t data8; + uint32_t data32; + uint8_t bytes[32]; +} SMCParamStruct; + +static IOReturn smc_call_struct_method(uint32_t selector, + SMCParamStruct *inputStruct, + SMCParamStruct *outputStruct) +{ + IOReturn ret; + + size_t inputStructCnt = sizeof(SMCParamStruct); + size_t outputStructCnt = sizeof(SMCParamStruct); + + io_service_t smcService = IO_OBJECT_NULL; + io_connect_t smcConnect = IO_OBJECT_NULL; + + smcService = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching("AppleSMC")); + if (smcService == IO_OBJECT_NULL) { + ret = kIOReturnNotFound; + goto exit; + } + + ret = IOServiceOpen(smcService, mach_task_self(), 1, &smcConnect); + if (ret != kIOReturnSuccess) { + smcConnect = IO_OBJECT_NULL; + goto exit; + } + if (smcConnect == IO_OBJECT_NULL) { + ret = kIOReturnError; + goto exit; + } + + ret = IOConnectCallMethod(smcConnect, kSMCUserClientOpen, + NULL, 0, NULL, 0, + NULL, NULL, NULL, NULL); + if (ret != kIOReturnSuccess) { + goto exit; + } + + ret = IOConnectCallStructMethod(smcConnect, selector, + inputStruct, inputStructCnt, + outputStruct, &outputStructCnt); + +exit: + if (smcConnect != IO_OBJECT_NULL) { + IOConnectCallMethod(smcConnect, kSMCUserClientClose, + NULL, 0, NULL, 0, NULL, + NULL, NULL, NULL); + IOServiceClose(smcConnect); + } + + return ret; +} + +static IOReturn smc_read_key(uint32_t key, + uint8_t *bytes, + IOByteCount *dataSize) +{ + IOReturn ret; + + SMCParamStruct inputStruct; + SMCParamStruct outputStruct; + + if (key == 0 || bytes == NULL) { + ret = kIOReturnCannotWire; + goto exit; + } + + /* determine key's data size */ + memset(&inputStruct, 0, sizeof(SMCParamStruct)); + inputStruct.data8 = kSMCGetKeyInfo; + inputStruct.key = key; + + memset(&outputStruct, 0, sizeof(SMCParamStruct)); + ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct); + if (ret != kIOReturnSuccess) { + goto exit; + } + if (outputStruct.result == kSMCKeyNotFound) { + ret = kIOReturnNotFound; + goto exit; + } + if (outputStruct.result != kSMCSuccess) { + ret = kIOReturnInternalError; + goto exit; + } + + /* get key value */ + memset(&inputStruct, 0, sizeof(SMCParamStruct)); + inputStruct.data8 = kSMCReadKey; + inputStruct.key = key; + inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize; + + memset(&outputStruct, 0, sizeof(SMCParamStruct)); + ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct); + if (ret != kIOReturnSuccess) { + goto exit; + } + if (outputStruct.result == kSMCKeyNotFound) { + ret = kIOReturnNotFound; + goto exit; + } + if (outputStruct.result != kSMCSuccess) { + ret = kIOReturnInternalError; + goto exit; + } + + memset(bytes, 0, *dataSize); + if (*dataSize > inputStruct.keyInfo.dataSize) { + *dataSize = inputStruct.keyInfo.dataSize; + } + memcpy(bytes, outputStruct.bytes, *dataSize); + +exit: + return ret; +} +#endif + /* #define DEBUG_SMC */ #define APPLESMC_DEFAULT_IOBASE 0x300 @@ -315,6 +480,7 @@ static const MemoryRegionOps applesmc_err_io_ops = { static void applesmc_isa_realize(DeviceState *dev, Error **errp) { AppleSMCState *s = APPLE_SMC(dev); + bool valid_key = false; memory_region_init_io(&s->io_data, OBJECT(s), &applesmc_data_io_ops, s, "applesmc-data", 1); @@ -331,7 +497,31 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp) isa_register_ioport(&s->parent_obj, &s->io_err, s->iobase + APPLESMC_ERR_PORT); - if (!s->osk || (strlen(s->osk) != 64)) { + if (s->osk) { + valid_key = strlen(s->osk) == 64; + } else { +#if defined(__APPLE__) && defined(__MACH__) + IOReturn ret; + IOByteCount size = 32; + + ret = smc_read_key('OSK0', (uint8_t *) default_osk, &size); + if (ret != kIOReturnSuccess) { + goto failure; + } + + ret = smc_read_key('OSK1', (uint8_t *) default_osk + size, &size); + if (ret != kIOReturnSuccess) { + goto failure; + } + + warn_report("Using AppleSMC with host key"); + valid_key = true; + s->osk = default_osk; +failure:; +#endif + } + + if (!valid_key) { warn_report("Using AppleSMC with invalid key"); s->osk = default_osk; } diff --git a/meson b/meson index 776acd2a80..b25d94e7c7 160000 --- a/meson +++ b/meson @@ -1 +1 @@ -Subproject commit 776acd2a805c9b42b4f0375150977df42130317f +Subproject commit b25d94e7c77fda05a7fdfe8afe562cf9760d69da diff --git a/meson.build b/meson.build index 60f4f45165..7b596fdcd9 100644 --- a/meson.build +++ b/meson.build @@ -1,14 +1,10 @@ -project('qemu', ['c'], meson_version: '>=0.55.0', - default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto'] + - (meson.version().version_compare('>=0.56.0') ? [ 'b_staticpic=false' ] : []), - version: run_command('head', meson.source_root() / 'VERSION').stdout().strip()) +project('qemu', ['c'], meson_version: '>=0.58.2', + default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto', + 'b_staticpic=false'], + version: files('VERSION')) not_found = dependency('', required: false) -if meson.version().version_compare('>=0.56.0') - keyval = import('keyval') -else - keyval = import('unstable-keyval') -endif +keyval = import('keyval') ss = import('sourceset') fs = import('fs') @@ -1972,21 +1968,21 @@ genh += configure_file(output: 'config-host.h', configuration: config_host_data) hxtool = find_program('scripts/hxtool') shaderinclude = find_program('scripts/shaderinclude.pl') qapi_gen = find_program('scripts/qapi-gen.py') -qapi_gen_depends = [ meson.source_root() / 'scripts/qapi/__init__.py', - meson.source_root() / 'scripts/qapi/commands.py', - meson.source_root() / 'scripts/qapi/common.py', - meson.source_root() / 'scripts/qapi/error.py', - meson.source_root() / 'scripts/qapi/events.py', - meson.source_root() / 'scripts/qapi/expr.py', - meson.source_root() / 'scripts/qapi/gen.py', - meson.source_root() / 'scripts/qapi/introspect.py', - meson.source_root() / 'scripts/qapi/parser.py', - meson.source_root() / 'scripts/qapi/schema.py', - meson.source_root() / 'scripts/qapi/source.py', - meson.source_root() / 'scripts/qapi/types.py', - meson.source_root() / 'scripts/qapi/visit.py', - meson.source_root() / 'scripts/qapi/common.py', - meson.source_root() / 'scripts/qapi-gen.py' +qapi_gen_depends = [ meson.current_source_dir() / 'scripts/qapi/__init__.py', + meson.current_source_dir() / 'scripts/qapi/commands.py', + meson.current_source_dir() / 'scripts/qapi/common.py', + meson.current_source_dir() / 'scripts/qapi/error.py', + meson.current_source_dir() / 'scripts/qapi/events.py', + meson.current_source_dir() / 'scripts/qapi/expr.py', + meson.current_source_dir() / 'scripts/qapi/gen.py', + meson.current_source_dir() / 'scripts/qapi/introspect.py', + meson.current_source_dir() / 'scripts/qapi/parser.py', + meson.current_source_dir() / 'scripts/qapi/schema.py', + meson.current_source_dir() / 'scripts/qapi/source.py', + meson.current_source_dir() / 'scripts/qapi/types.py', + meson.current_source_dir() / 'scripts/qapi/visit.py', + meson.current_source_dir() / 'scripts/qapi/common.py', + meson.current_source_dir() / 'scripts/qapi-gen.py' ] tracetool = [ @@ -2635,14 +2631,14 @@ foreach target : target_dirs if target.endswith('-softmmu') execs = [{ 'name': 'qemu-system-' + target_name, - 'gui': false, + 'win_subsystem': 'console', 'sources': files('softmmu/main.c'), 'dependencies': [] }] if targetos == 'windows' and (sdl.found() or gtk.found()) execs += [{ 'name': 'qemu-system-' + target_name + 'w', - 'gui': true, + 'win_subsystem': 'windows', 'sources': files('softmmu/main.c'), 'dependencies': [] }] @@ -2651,7 +2647,7 @@ foreach target : target_dirs specific_fuzz = specific_fuzz_ss.apply(config_target, strict: false) execs += [{ 'name': 'qemu-fuzz-' + target_name, - 'gui': false, + 'win_subsystem': 'console', 'sources': specific_fuzz.sources(), 'dependencies': specific_fuzz.dependencies(), }] @@ -2659,7 +2655,7 @@ foreach target : target_dirs else execs = [{ 'name': 'qemu-' + target_name, - 'gui': false, + 'win_subsystem': 'console', 'sources': [], 'dependencies': [] }] @@ -2678,7 +2674,7 @@ foreach target : target_dirs link_language: link_language, link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []), link_args: link_args, - gui_app: exe['gui']) + win_subsystem: exe['win_subsystem']) if targetos == 'darwin' icon = 'pc-bios/qemu.rsrc' @@ -2863,13 +2859,13 @@ summary_info = {} summary_info += {'git': config_host['GIT']} summary_info += {'make': config_host['MAKE']} summary_info += {'python': '@0@ (version: @1@)'.format(python.full_path(), python.language_version())} -summary_info += {'sphinx-build': sphinx_build.found()} +summary_info += {'sphinx-build': sphinx_build} if config_host.has_key('HAVE_GDB_BIN') summary_info += {'gdb': config_host['HAVE_GDB_BIN']} endif summary_info += {'genisoimage': config_host['GENISOIMAGE']} if targetos == 'windows' and config_host.has_key('CONFIG_GUEST_AGENT') - summary_info += {'wixl': wixl.found() ? wixl.full_path() : false} + summary_info += {'wixl': wixl} endif if slirp_opt != 'disabled' and 'CONFIG_SLIRP_SMBD' in config_host summary_info += {'smbd': config_host['CONFIG_SMBD_COMMAND']} @@ -2960,7 +2956,7 @@ if get_option('cfi') summary_info += {'CFI debug support': get_option('cfi_debug')} endif summary_info += {'strip binaries': get_option('strip')} -summary_info += {'sparse': sparse.found() ? sparse.full_path() : false} +summary_info += {'sparse': sparse} summary_info += {'mingw32 support': targetos == 'windows'} # snarf the cross-compilation information for tests @@ -3032,19 +3028,19 @@ if have_block 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 += {'FUSE exports': fuse.found()} + summary_info += {'FUSE exports': fuse} endif summary(summary_info, bool_yn: true, section: 'Block layer support') # Crypto summary_info = {} summary_info += {'TLS priority': config_host['CONFIG_TLS_PRIORITY']} -summary_info += {'GNUTLS support': gnutls.found()} -summary_info += {'GNUTLS crypto': gnutls_crypto.found()} -# TODO: add back version -summary_info += {'libgcrypt': gcrypt.found()} -# TODO: add back version -summary_info += {'nettle': nettle.found()} +summary_info += {'GNUTLS support': gnutls} +if gnutls.found() + summary_info += {' GNUTLS crypto': gnutls_crypto.found()} +endif +summary_info += {'libgcrypt': gcrypt} +summary_info += {'nettle': nettle} if nettle.found() summary_info += {' XTS': xts != 'private'} endif @@ -3056,76 +3052,72 @@ summary(summary_info, bool_yn: true, section: 'Crypto') # Libraries summary_info = {} if targetos == 'darwin' - summary_info += {'Cocoa support': cocoa.found()} + summary_info += {'Cocoa support': cocoa} endif -# TODO: add back version -summary_info += {'SDL support': sdl.found()} -summary_info += {'SDL image support': sdl_image.found()} -# TODO: add back version -summary_info += {'GTK support': gtk.found()} -summary_info += {'pixman': pixman.found()} -# TODO: add back version -summary_info += {'VTE support': vte.found()} -# TODO: add back version -summary_info += {'slirp support': slirp_opt == 'disabled' ? false : slirp_opt} -summary_info += {'libtasn1': tasn1.found()} -summary_info += {'PAM': pam.found()} -summary_info += {'iconv support': iconv.found()} -summary_info += {'curses support': curses.found()} -# TODO: add back version -summary_info += {'virgl support': virgl.found()} -summary_info += {'curl support': curl.found()} -summary_info += {'Multipath support': mpathpersist.found()} -summary_info += {'VNC support': vnc.found()} +summary_info += {'SDL support': sdl} +summary_info += {'SDL image support': sdl_image} +summary_info += {'GTK support': gtk} +summary_info += {'pixman': pixman} +summary_info += {'VTE support': vte} +summary_info += {'slirp support': slirp_opt == 'internal' ? slirp_opt : slirp} +summary_info += {'libtasn1': tasn1} +summary_info += {'PAM': pam} +summary_info += {'iconv support': iconv} +summary_info += {'curses support': curses} +summary_info += {'virgl support': virgl} +summary_info += {'curl support': curl} +summary_info += {'Multipath support': mpathpersist} +summary_info += {'VNC support': vnc} if vnc.found() - summary_info += {'VNC SASL support': sasl.found()} - summary_info += {'VNC JPEG support': jpeg.found()} - summary_info += {'VNC PNG support': png.found()} + summary_info += {'VNC SASL support': sasl} + summary_info += {'VNC JPEG support': jpeg} + summary_info += {'VNC PNG support': png} endif -summary_info += {'brlapi support': brlapi.found()} +summary_info += {'brlapi support': brlapi} summary_info += {'vde support': config_host.has_key('CONFIG_VDE')} summary_info += {'netmap support': config_host.has_key('CONFIG_NETMAP')} summary_info += {'Linux AIO support': config_host.has_key('CONFIG_LINUX_AIO')} -summary_info += {'Linux io_uring support': linux_io_uring.found()} -summary_info += {'ATTR/XATTR support': libattr.found()} +summary_info += {'Linux io_uring support': linux_io_uring} +summary_info += {'ATTR/XATTR support': libattr} summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')} summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')} summary_info += {'fdt support': fdt_opt == 'disabled' ? false : fdt_opt} -summary_info += {'libcap-ng support': libcap_ng.found()} -summary_info += {'bpf support': libbpf.found()} +summary_info += {'libcap-ng support': libcap_ng} +summary_info += {'bpf support': libbpf} # TODO: add back protocol and server version summary_info += {'spice support': config_host.has_key('CONFIG_SPICE')} -summary_info += {'rbd support': rbd.found()} +summary_info += {'rbd support': rbd} summary_info += {'xfsctl support': config_host.has_key('CONFIG_XFS')} -summary_info += {'smartcard support': cacard.found()} -summary_info += {'U2F support': u2f.found()} -summary_info += {'libusb': libusb.found()} -summary_info += {'usb net redir': usbredir.found()} +summary_info += {'smartcard support': cacard} +summary_info += {'U2F support': u2f} +summary_info += {'libusb': libusb} +summary_info += {'usb net redir': usbredir} summary_info += {'OpenGL support': config_host.has_key('CONFIG_OPENGL')} -summary_info += {'GBM': gbm.found()} -summary_info += {'libiscsi support': libiscsi.found()} -summary_info += {'libnfs support': libnfs.found()} +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')} endif endif -summary_info += {'seccomp support': seccomp.found()} -summary_info += {'GlusterFS support': glusterfs.found()} +summary_info += {'seccomp support': seccomp} +summary_info += {'GlusterFS support': glusterfs} summary_info += {'TPM support': config_host.has_key('CONFIG_TPM')} summary_info += {'libssh support': config_host.has_key('CONFIG_LIBSSH')} -summary_info += {'lzo support': lzo.found()} -summary_info += {'snappy support': snappy.found()} -summary_info += {'bzip2 support': libbzip2.found()} -summary_info += {'lzfse support': liblzfse.found()} -summary_info += {'zstd support': zstd.found()} +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 += {'libxml2': libxml2.found()} -summary_info += {'capstone': capstone_opt == 'disabled' ? false : capstone_opt} -summary_info += {'libpmem support': libpmem.found()} -summary_info += {'libdaxctl support': libdaxctl.found()} -summary_info += {'libudev': libudev.found()} +summary_info += {'libxml2': libxml2} +summary_info += {'capstone': capstone_opt == 'internal' ? capstone_opt : capstone} +summary_info += {'libpmem support': libpmem} +summary_info += {'libdaxctl support': libdaxctl} +summary_info += {'libudev': libudev} +# Dummy dependency, keep .found() summary_info += {'FUSE lseek': fuse_lseek.found()} summary(summary_info, bool_yn: true, section: 'Dependencies') diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 35f5ef688d..9aba7d9c22 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -1215,7 +1215,10 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) { DBMSaveState *s = &((DBMState *)opaque)->save; SaveBitmapState *dbms = NULL; + + qemu_mutex_lock_iothread(); if (init_dirty_bitmap_migration(s) < 0) { + qemu_mutex_unlock_iothread(); return -1; } @@ -1223,7 +1226,7 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) send_bitmap_start(f, s, dbms); } qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS); - + qemu_mutex_unlock_iothread(); return 0; } diff --git a/migration/migration.c b/migration/migration.c index bb909781b7..6ac807ef3d 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -3168,7 +3168,10 @@ static void migration_completion(MigrationState *s) } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { trace_migration_completion_postcopy_end(); + qemu_mutex_lock_iothread(); qemu_savevm_state_complete_postcopy(s->to_dst_file); + qemu_mutex_unlock_iothread(); + trace_migration_completion_postcopy_end_after_complete(); } else if (s->state == MIGRATION_STATUS_CANCELLING) { goto fail; diff --git a/plugins/meson.build b/plugins/meson.build index bfd5c9822a..aeb386ebae 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -2,9 +2,9 @@ plugin_ldflags = [] # Modules need more symbols than just those in plugins/qemu-plugins.symbols if not enable_modules if 'CONFIG_HAS_LD_DYNAMIC_LIST' in config_host - plugin_ldflags = ['-Wl,--dynamic-list=' + (meson.build_root() / 'qemu-plugins-ld.symbols')] + plugin_ldflags = ['-Wl,--dynamic-list=' + (meson.project_build_root() / 'qemu-plugins-ld.symbols')] elif 'CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST' in config_host - plugin_ldflags = ['-Wl,-exported_symbols_list,' + (meson.build_root() / 'qemu-plugins-ld64.symbols')] + plugin_ldflags = ['-Wl,-exported_symbols_list,' + (meson.project_build_root() / 'qemu-plugins-ld64.symbols')] endif endif diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py index ee072c0502..02c0453e67 100644 --- a/scripts/mtest2make.py +++ b/scripts/mtest2make.py @@ -60,11 +60,8 @@ def process_tests(test, targets, suites): if test['workdir'] is not None: print('.test.dir.%d := %s' % (i, shlex.quote(test['workdir']))) - if 'depends' in test: - deps = (targets.get(x, []) for x in test['depends']) - deps = itertools.chain.from_iterable(deps) - else: - deps = ['all'] + deps = (targets.get(x, []) for x in test['depends']) + deps = itertools.chain.from_iterable(deps) print('.test.name.%d := %s' % (i, test['name'])) print('.test.driver.%d := %s' % (i, driver)) diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index 6fd9360b74..c6d858ffb2 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -156,7 +156,8 @@ dectree_generated = custom_target( 'dectree_generated.h.inc', output: 'dectree_generated.h.inc', depends: [iset_py], - command: ['env', 'PYTHONPATH=' + meson.current_build_dir(), files('dectree.py'), '@OUTPUT@'], + env: {'PYTHONPATH': meson.current_build_dir()}, + command: [python, files('dectree.py'), '@OUTPUT@'], ) hexagon_ss.add(dectree_generated) diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c index 0227cb5177..d8e6583171 100644 --- a/target/i386/sev-stub.c +++ b/target/i386/sev-stub.c @@ -81,3 +81,8 @@ sev_get_attestation_report(const char *mnonce, Error **errp) error_setg(errp, "SEV is not available in this QEMU"); return NULL; } + +bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) +{ + g_assert_not_reached(); +} diff --git a/target/i386/sev.c b/target/i386/sev.c index fa7210473a..bcd9260fa4 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -23,6 +23,7 @@ #include "qemu/base64.h" #include "qemu/module.h" #include "qemu/uuid.h" +#include "crypto/hash.h" #include "sysemu/kvm.h" #include "sev_i386.h" #include "sysemu/sysemu.h" @@ -83,6 +84,32 @@ typedef struct __attribute__((__packed__)) SevInfoBlock { uint32_t reset_addr; } SevInfoBlock; +#define SEV_HASH_TABLE_RV_GUID "7255371f-3a3b-4b04-927b-1da6efa8d454" +typedef struct QEMU_PACKED SevHashTableDescriptor { + /* SEV hash table area guest address */ + uint32_t base; + /* SEV hash table area size (in bytes) */ + uint32_t size; +} SevHashTableDescriptor; + +/* hard code sha256 digest size */ +#define HASH_SIZE 32 + +typedef struct QEMU_PACKED SevHashTableEntry { + QemuUUID guid; + uint16_t len; + uint8_t hash[HASH_SIZE]; +} SevHashTableEntry; + +typedef struct QEMU_PACKED SevHashTable { + QemuUUID guid; + uint16_t len; + SevHashTableEntry cmdline; + SevHashTableEntry initrd; + SevHashTableEntry kernel; + uint8_t padding[]; +} SevHashTable; + static SevGuestState *sev_guest; static Error *sev_mig_blocker; @@ -1071,6 +1098,116 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size) return 0; } +static const QemuUUID sev_hash_table_header_guid = { + .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93, + 0xd4, 0x11, 0xfd, 0x21) +}; + +static const QemuUUID sev_kernel_entry_guid = { + .data = UUID_LE(0x4de79437, 0xabd2, 0x427f, 0xb8, 0x35, 0xd5, 0xb1, + 0x72, 0xd2, 0x04, 0x5b) +}; +static const QemuUUID sev_initrd_entry_guid = { + .data = UUID_LE(0x44baf731, 0x3a2f, 0x4bd7, 0x9a, 0xf1, 0x41, 0xe2, + 0x91, 0x69, 0x78, 0x1d) +}; +static const QemuUUID sev_cmdline_entry_guid = { + .data = UUID_LE(0x97d02dd8, 0xbd20, 0x4c94, 0xaa, 0x78, 0xe7, 0x71, + 0x4d, 0x36, 0xab, 0x2a) +}; + +/* + * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page + * which is included in SEV's initial memory measurement. + */ +bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp) +{ + uint8_t *data; + SevHashTableDescriptor *area; + SevHashTable *ht; + uint8_t cmdline_hash[HASH_SIZE]; + uint8_t initrd_hash[HASH_SIZE]; + uint8_t kernel_hash[HASH_SIZE]; + uint8_t *hashp; + size_t hash_len = HASH_SIZE; + int aligned_len; + + if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) { + error_setg(errp, "SEV: kernel specified but OVMF has no hash table guid"); + return false; + } + area = (SevHashTableDescriptor *)data; + + /* + * Calculate hash of kernel command-line with the terminating null byte. If + * the user doesn't supply a command-line via -append, the 1-byte "\0" will + * be used. + */ + hashp = cmdline_hash; + if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->cmdline_data, + ctx->cmdline_size, &hashp, &hash_len, errp) < 0) { + return false; + } + assert(hash_len == HASH_SIZE); + + /* + * Calculate hash of initrd. If the user doesn't supply an initrd via + * -initrd, an empty buffer will be used (ctx->initrd_size == 0). + */ + hashp = initrd_hash; + if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->initrd_data, + ctx->initrd_size, &hashp, &hash_len, errp) < 0) { + return false; + } + assert(hash_len == HASH_SIZE); + + /* Calculate hash of the kernel */ + hashp = kernel_hash; + struct iovec iov[2] = { + { .iov_base = ctx->setup_data, .iov_len = ctx->setup_size }, + { .iov_base = ctx->kernel_data, .iov_len = ctx->kernel_size } + }; + if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256, iov, ARRAY_SIZE(iov), + &hashp, &hash_len, errp) < 0) { + return false; + } + assert(hash_len == HASH_SIZE); + + /* + * Populate the hashes table in the guest's memory at the OVMF-designated + * area for the SEV hashes table + */ + ht = qemu_map_ram_ptr(NULL, area->base); + + ht->guid = sev_hash_table_header_guid; + ht->len = sizeof(*ht); + + ht->cmdline.guid = sev_cmdline_entry_guid; + ht->cmdline.len = sizeof(ht->cmdline); + memcpy(ht->cmdline.hash, cmdline_hash, sizeof(ht->cmdline.hash)); + + ht->initrd.guid = sev_initrd_entry_guid; + ht->initrd.len = sizeof(ht->initrd); + memcpy(ht->initrd.hash, initrd_hash, sizeof(ht->initrd.hash)); + + ht->kernel.guid = sev_kernel_entry_guid; + ht->kernel.len = sizeof(ht->kernel); + memcpy(ht->kernel.hash, kernel_hash, sizeof(ht->kernel.hash)); + + /* When calling sev_encrypt_flash, the length has to be 16 byte aligned */ + aligned_len = ROUND_UP(ht->len, 16); + if (aligned_len != ht->len) { + /* zero the excess data so the measurement can be reliably calculated */ + memset(ht->padding, 0, aligned_len - ht->len); + } + + if (sev_encrypt_flash((uint8_t *)ht, aligned_len, errp) < 0) { + return false; + } + + return true; +} + static void sev_register_types(void) { diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h index ae6d840478..2afe108069 100644 --- a/target/i386/sev_i386.h +++ b/target/i386/sev_i386.h @@ -28,6 +28,17 @@ #define SEV_POLICY_DOMAIN 0x10 #define SEV_POLICY_SEV 0x20 +typedef struct SevKernelLoaderContext { + char *setup_data; + size_t setup_size; + char *kernel_data; + size_t kernel_size; + char *initrd_data; + size_t initrd_size; + char *cmdline_data; + size_t cmdline_size; +} SevKernelLoaderContext; + extern bool sev_es_enabled(void); extern uint64_t sev_get_me_mask(void); extern SevInfo *sev_get_info(void); @@ -37,5 +48,6 @@ extern char *sev_get_launch_measurement(void); extern SevCapability *sev_get_capabilities(Error **errp); extern SevAttestationReport * sev_get_attestation_report(const char *mnonce, Error **errp); +extern bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp); #endif diff --git a/target/xtensa/cores.list b/target/xtensa/cores.list new file mode 100644 index 0000000000..5772a00ab2 --- /dev/null +++ b/target/xtensa/cores.list @@ -0,0 +1,9 @@ +core-dc232b.c +core-dc233c.c +core-de212.c +core-de233_fpu.c +core-dsp3400.c +core-fsf.c +core-sample_controller.c +core-test_kc705_be.c +core-test_mmuhifi_c3.c diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh index 396b264be9..df66d09393 100755 --- a/target/xtensa/import_core.sh +++ b/target/xtensa/import_core.sh @@ -66,3 +66,6 @@ static XtensaConfig $NAME __attribute__((unused)) = { REGISTER_CORE($NAME) EOF + +grep -qxf core-${NAME}.c "$BASE"/cores.list || \ + echo core-${NAME}.c >> "$BASE"/cores.list diff --git a/target/xtensa/meson.build b/target/xtensa/meson.build index 7c4efa6c62..20bbf9b335 100644 --- a/target/xtensa/meson.build +++ b/target/xtensa/meson.build @@ -1,7 +1,7 @@ xtensa_ss = ss.source_set() -xtensa_cores = run_command('sh', '-c', 'cd $MESON_SOURCE_ROOT/$MESON_SUBDIR ; ls -1 core-*.c') -xtensa_ss.add(files(xtensa_cores.stdout().strip().split('\n'))) +xtensa_cores = fs.read('cores.list') +xtensa_ss.add(files(xtensa_cores.strip().split('\n'))) xtensa_ss.add(files( 'cpu.c', diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index 6187efbd58..df5acfd08b 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -1,5 +1,5 @@ test_env = environment() -test_env.set('PYTHONPATH', meson.source_root() / 'scripts') +test_env.set('PYTHONPATH', meson.project_source_root() / 'scripts') test_env.set('PYTHONIOENCODING', 'utf-8') schemas = [ @@ -248,7 +248,7 @@ if build_docs # clutter up the build dir with the cache. command: [SPHINX_ARGS, '-b', 'text', '-E', - '-c', meson.source_root() / 'docs', + '-c', meson.project_source_root() / 'docs', '-D', 'master_doc=doc-good', meson.current_source_dir(), meson.current_build_dir()]) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 19444d4752..c9d8458062 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -275,7 +275,7 @@ foreach dir : target_dirs qtest_env.set('QTEST_QEMU_IMG', './qemu-img') test_deps += [qemu_img] endif - qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vmstate-daemon.sh') + qtest_env.set('G_TEST_DBUS_DAEMON', meson.project_source_root() / 'tests/dbus-vmstate-daemon.sh') qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base) if have_tools and have_vhost_user_blk_server qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon') diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 5736d285b2..7c297d7e5c 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -43,7 +43,7 @@ tests = { 'test-keyval': [testqapi], 'test-logging': [], 'test-uuid': [], - 'ptimer-test': ['ptimer-test-stubs.c', meson.source_root() / 'hw/core/ptimer.c'], + 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw/core/ptimer.c'], 'test-qapi-util': [], } diff --git a/trace/meson.build b/trace/meson.build index e401e7c415..b8f95de200 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -4,7 +4,7 @@ specific_ss.add(files('control-target.c')) trace_events_files = [] dtrace = find_program('dtrace', required: 'CONFIG_TRACE_DTRACE' in config_host) foreach dir : [ '.' ] + trace_events_subdirs - trace_events_file = meson.source_root() / dir / 'trace-events' + trace_events_file = meson.project_source_root() / dir / 'trace-events' trace_events_files += [ trace_events_file ] group_name = dir == '.' ? 'root' : dir.underscorify() group = '--group=' + group_name @@ -70,7 +70,7 @@ foreach d : [ ] gen = custom_target(d[0], output: d[0], - input: meson.source_root() / 'trace-events', + input: meson.project_source_root() / 'trace-events', command: [ tracetool, '--group=root', '--format=@0@'.format(d[1]), '@INPUT@', '@OUTPUT@' ], depend_files: tracetool_depends) specific_ss.add(when: 'CONFIG_TCG', if_true: gen)