Merge tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu into staging Merge crypto and other misc fixes / features * Increase minimum gnutls to 3.7.5 * Increase minimum libgcrypt to 1.9.4 * Increase minimum nettle to 3.7.3 * Drop obsolete in-tree XTS impl * Fix memory leak when loading certificates * Remove/reduce duplication when loading certifcates * Fix possible crash when certificates are unloaded while an active TLS connection is using when in a TLS handshake operation * Deprecate use of dh-params.pem file * Document how to create certificates with Post-Quantum Cryptography compliant algorithms. * Support loading multiple certificate identities to allow support for Post-Quantum crypto in parallel with traditional RSA/ECC * Add "-run-with exit-with-parent=on" parameter * Flush pending errors when seeing ENOBUFS with a zero-copy send attempt * Fix data buffer parameters in hash & IO channel APIs to use 'void *' # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmkIr/8ACgkQvobrtBUQ # T9+2RhAAhEak/krdlTJw8OlJonUop7G5mlLU2TEoX0duRORcFhScsdSwb2pyc/wM # tnwfWXsnsKFItJx1y3STkOICtdNqizGoU3+c7wl4anQBurydu+XTs4ESBtVJtMYr # 1lTYvp0HFyKvaXwDWKE+ztltlJiog51tHPDLUIBCnyJysLVqxCHMHmkbG46IPBZo # A2XXxp3j/VBPmhls0JHpbAD4iVE3PChdK7zhyeGe/rld9+0JA12EPCvZ5Uokdj41 # aYP/okvnVH1atucoygPdDE3P5GYBKaSXZUWqzfkKhU7FgaF2863Td7ff1ip+WyWN # FFPNEU1hVg+T5hfsZVQmmIFDdSJWqoZaZM/WJVYdrRY4dKUCPnJ9OINbbnhuWz5E # JFmZOPibRZKQ44XcHX49JRfJEBvoq1z9OT1r7HkEP4D9/O7V/riIunbAESMk0sgi # 0/fatvdhNKMN6YBQM3mtN3yNOcfRSWFtSy9XS9zDjdpEKT7ui2t9FC0ZNSP0FRkS # aTY31FyacjHwU3zaoh6NoqqpxV9wwHrgsJwNbA/IztjmX/jvGG0Gb/sXVEqM59tR # e3VWTmlmZ1T8OLImh1hG4t+nY+XzI64QpVX8H9RCGm21o28DyTcOnTFK4OyIfWe5 # ttnNfEJN8WCVCsA8tcM8yAbZ/0qXrYfiZSO7hq79wE7LvyholAQ= # =9ESG # -----END PGP SIGNATURE----- # gpg: Signature made Mon 03 Nov 2025 02:37:03 PM CET # gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [unknown] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu: (32 commits) docs: creation of x509 certs compliant with post-quantum crypto crypto: support upto 5 parallel certificate identities crypto: expand logic to cope with multiple certificate identities crypto: avoid loading the identity certs twice crypto: avoid loading the CA certs twice crypto: deprecate use of external dh-params.pem file crypto: make TLS credentials structs private crypto: fix lifecycle handling of gnutls credentials objects crypto: introduce a wrapper around gnutls credentials crypto: introduce method for reloading TLS creds crypto: reduce duplication in handling TLS priority strings crypto: remove duplication loading x509 CA cert crypto: shorten the endpoint == server check in TLS creds crypto: move release of DH parameters into TLS creds parent crypto: remove needless indirection via parent_obj field crypto: use g_autofree when loading x509 credentials crypto: move check for TLS creds 'dir' property crypto: remove redundant access() checks before loading certs crypto: replace stat() with access() for credential checks crypto: add missing free of certs array ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS index a6a1d36..93cef88 100644 --- a/MAINTAINERS +++ b/MAINTAINERS
@@ -3908,6 +3908,17 @@ F: tests/data/uefi-boot-images/ F: tests/uefi-test-tools/ +IGVM Firmware +M: Gerd Hoffmann <kraxel@redhat.com> +M: Stefano Garzarella <sgarzare@redhat.com> +R: Ani Sinha <anisinha@redhat.com> +S: Maintained +F: backends/igvm*.c +F: docs/system/igvm.rst +F: include/system/igvm*.h +F: stubs/igvm.c +F: target/i386/igvm.c + VT-d Emulation M: Michael S. Tsirkin <mst@redhat.com> R: Jason Wang <jasowang@redhat.com> @@ -4412,6 +4423,7 @@ M: Thomas Huth <thuth@redhat.com> R: Philippe Mathieu-Daudé <philmd@linaro.org> R: Daniel P. Berrange <berrange@redhat.com> +S: Maintained F: docs/devel/testing/functional.rst F: scripts/clean_functional_cache.py F: tests/functional/qemu_test/
diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 2fb4643..f84342e 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -197,7 +197,7 @@ qemu_guest_random_seed_thread_part2(cpu->random_seed); /* wait for initial kick-off after machine start */ - while (first_cpu->stopped) { + while (cpu_is_stopped(first_cpu)) { qemu_cond_wait_bql(first_cpu->halt_cond); /* process any pending work */
diff --git a/backends/igvm-cfg.c b/backends/igvm-cfg.c index 45df63e..d00acf3 100644 --- a/backends/igvm-cfg.c +++ b/backends/igvm-cfg.c
@@ -12,7 +12,7 @@ #include "qemu/osdep.h" #include "system/igvm-cfg.h" -#include "igvm.h" +#include "system/igvm.h" #include "qom/object_interfaces.h" static char *get_igvm(Object *obj, Error **errp)
diff --git a/backends/igvm.c b/backends/igvm.c index 9ad4158..905bd8d 100644 --- a/backends/igvm.c +++ b/backends/igvm.c
@@ -11,8 +11,9 @@ #include "qemu/osdep.h" -#include "igvm.h" #include "qapi/error.h" +#include "qemu/target-info-qapi.h" +#include "system/igvm.h" #include "system/memory.h" #include "system/address-spaces.h" #include "hw/core/cpu.h" @@ -431,18 +432,6 @@ return 0; } - /* - * A confidential guest support object must be provided for setting - * a VP context. - */ - if (!ctx->cgs) { - error_setg( - errp, - "A VP context is present in the IGVM file but is not supported " - "by the current system."); - return -1; - } - data_handle = igvm_get_header_data(ctx->file, IGVM_HEADER_SECTION_DIRECTIVE, ctx->current_header_index); if (data_handle < 0) { @@ -452,9 +441,21 @@ } data = (uint8_t *)igvm_get_buffer(ctx->file, data_handle); - result = ctx->cgsc->set_guest_state( - vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle), - CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp); + + if (ctx->cgs) { + result = ctx->cgsc->set_guest_state( + vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle), + CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp); + } else if (target_arch() == SYS_EMU_TARGET_X86_64) { + result = qigvm_x86_set_vp_context(data, vp_context->vp_index, errp); + } else { + error_setg( + errp, + "A VP context is present in the IGVM file but is not supported " + "by the current system."); + result = -1; + } + igvm_free_buffer(ctx->file, data_handle); if (result < 0) { return result; @@ -543,6 +544,8 @@ Error **errp) { const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data; + int (*get_mem_map_entry)(int index, ConfidentialGuestMemoryMapEntry *entry, + Error **errp) = NULL; QIgvmParameterData *param_entry; int max_entry_count; int entry = 0; @@ -550,7 +553,13 @@ ConfidentialGuestMemoryMapEntry cgmm_entry; int retval = 0; - if (!ctx->cgs) { + if (ctx->cgs && ctx->cgsc->get_mem_map_entry) { + get_mem_map_entry = ctx->cgsc->get_mem_map_entry; + + } else if (target_arch() == SYS_EMU_TARGET_X86_64) { + get_mem_map_entry = qigvm_x86_get_mem_map_entry; + + } else { error_setg(errp, "IGVM file contains a memory map but this is not supported " "by the current system."); @@ -565,9 +574,9 @@ param_entry->size / sizeof(IGVM_VHS_MEMORY_MAP_ENTRY); mm_entry = (IGVM_VHS_MEMORY_MAP_ENTRY *)param_entry->data; - retval = ctx->cgsc->get_mem_map_entry(entry, &cgmm_entry, errp); + retval = get_mem_map_entry(entry, &cgmm_entry, errp); while (retval == 0) { - if (entry > max_entry_count) { + if (entry >= max_entry_count) { error_setg( errp, "IGVM: guest memory map size exceeds parameter area defined in IGVM file"); @@ -598,8 +607,7 @@ IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED; break; } - retval = - ctx->cgsc->get_mem_map_entry(++entry, &cgmm_entry, errp); + retval = get_mem_map_entry(++entry, &cgmm_entry, errp); } if (retval < 0) { return retval;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index a3bb5aa..5841dfc 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c
@@ -396,7 +396,7 @@ uint64_t subregion_size; QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) { - subregion_size = int128_get64(subregion->size); + subregion_size = memory_region_size(subregion); if ((offset >= subregion->addr) && (offset + len) <= (subregion->addr + subregion_size)) { mr = subregion;
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 67e15c8..e0be4ee 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h
@@ -150,10 +150,6 @@ int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque); -/* Returns: 0 on success, -1 on error */ -int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, - void *ptr, size_t len, bool is_write); - /* vl.c */ void list_cpus(void);
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index e79e8e0..9615051 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h
@@ -689,6 +689,26 @@ void *opaque); /** + * cpu_memory_rw_debug: + * @cpu: The CPU whose memory is to be accessed + * @addr: guest virtual address + * @ptr: buffer with the data transferred + * @len: the number of bytes to read or write + * @is_write: indicates the transfer direction + * + * Take a virtual address, convert it to a physical address via + * an MMU lookup using the current settings of the specified CPU, + * and then perform the access (using address_space_rw() for + * reads or address_space_write_rom() for writes). + * + * This function is intended for use by the GDB stub and similar code. + * + * Returns: 0 on success, -1 on error + */ +int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, + void *ptr, size_t len, bool is_write); + +/** * cpu_get_crash_info: * @cpu: The CPU to get crash information for *
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 4e2436b..0d55c63 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h
@@ -271,6 +271,24 @@ bool bql_locked(void); /** + * mutex_is_bql: + * + * @mutex: the mutex pointer + * + * Returns whether the mutex is the BQL. + */ +bool mutex_is_bql(QemuMutex *mutex); + +/** + * bql_update_status: + * + * @locked: update status on whether the BQL is locked + * + * NOTE: this should normally only be invoked when the status changed. + */ +void bql_update_status(bool locked); + +/** * bql_block: Allow/deny releasing the BQL * * The Big QEMU Lock (BQL) is used to provide interior mutability to
diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 406d741..8b561cd 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h
@@ -786,11 +786,12 @@ } /** - * initclocks: + * qemu_init_clocks: + * @notify_cb: optional call-back for timer expiry * * Initialise the clock & timer infrastructure */ -void init_clocks(QEMUTimerListNotifyCB *notify_cb); +void qemu_init_clocks(QEMUTimerListNotifyCB *notify_cb); static inline int64_t get_max_clock_jump(void) {
diff --git a/backends/igvm.h b/include/system/igvm.h similarity index 64% rename from backends/igvm.h rename to include/system/igvm.h index a4abab0..48ce206 100644 --- a/backends/igvm.h +++ b/include/system/igvm.h
@@ -19,4 +19,11 @@ int qigvm_process_file(IgvmCfg *igvm, ConfidentialGuestSupport *cgs, bool onlyVpContext, Error **errp); +/* x86 native */ +int qigvm_x86_get_mem_map_entry(int index, + ConfidentialGuestMemoryMapEntry *entry, + Error **errp); +int qigvm_x86_set_vp_context(void *data, int index, + Error **errp); + #endif
diff --git a/scripts/device-crash-test b/scripts/device-crash-test index 1ecb966..c1576e8 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test
@@ -527,7 +527,7 @@ # Async QMP, when in use, is chatty about connection failures. # This script knowingly generates a ton of connection errors. # Silence this logger. - logging.getLogger('qemu.qmp.qmp_client').setLevel(logging.CRITICAL) + logging.getLogger('qemu.qmp.protocol').setLevel(logging.CRITICAL) fatal_failures = [] wl_stats = {}
diff --git a/stubs/igvm.c b/stubs/igvm.c new file mode 100644 index 0000000..17cd1e9 --- /dev/null +++ b/stubs/igvm.c
@@ -0,0 +1,26 @@ +/* + * QEMU IGVM, stubs + * + * Copyright (C) 2026 Red Hat + * + * Authors: + * Gerd Hoffmann <kraxel@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" + +#include "system/igvm.h" + +int qigvm_x86_get_mem_map_entry(int index, + ConfidentialGuestMemoryMapEntry *entry, + Error **errp) +{ + return -1; +} + +int qigvm_x86_set_vp_context(void *data, int index, Error **errp) +{ + return -1; +}
diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c index 6050c08..c89c9c7 100644 --- a/stubs/iothread-lock.c +++ b/stubs/iothread-lock.c
@@ -34,3 +34,12 @@ assert((new_value > bql_unlock_blocked) == increase); bql_unlock_blocked = new_value; } + +bool mutex_is_bql(QemuMutex *mutex) +{ + return false; +} + +void bql_update_status(bool locked) +{ +}
diff --git a/stubs/meson.build b/stubs/meson.build index 5d57746..27be2de 100644 --- a/stubs/meson.build +++ b/stubs/meson.build
@@ -74,6 +74,7 @@ stub_ss.add(files('dump.c')) stub_ss.add(files('cmos.c')) stub_ss.add(files('fw_cfg.c')) + stub_ss.add(files('igvm.c')) stub_ss.add(files('target-get-monitor-def.c')) stub_ss.add(files('target-monitor-defs.c')) stub_ss.add(files('win32-kbd-hook.c'))
diff --git a/system/cpus.c b/system/cpus.c index aa7bfcf..ef2d2f2 100644 --- a/system/cpus.c +++ b/system/cpus.c
@@ -480,10 +480,10 @@ void cpus_kick_thread(CPUState *cpu) { - if (cpu->thread_kicked) { + if (qatomic_read(&cpu->thread_kicked)) { return; } - cpu->thread_kicked = true; + qatomic_set(&cpu->thread_kicked, true); #ifndef _WIN32 int err = pthread_kill(cpu->thread->thread, SIG_IPI); @@ -524,6 +524,18 @@ QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked) +bool mutex_is_bql(QemuMutex *mutex) +{ + return mutex == &bql; +} + +void bql_update_status(bool locked) +{ + /* This function should only be used when an update happened.. */ + assert(bql_locked() != locked); + set_bql_locked(locked); +} + static uint32_t bql_unlock_blocked; void bql_block_unlock(bool increase) @@ -564,14 +576,12 @@ g_assert(!bql_locked()); bql_lock_fn(&bql, file, line); - set_bql_locked(true); } void bql_unlock(void) { g_assert(bql_locked()); g_assert(!bql_unlock_blocked); - set_bql_locked(false); qemu_mutex_unlock(&bql); }
diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 0a66e1f..6417775 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c
@@ -8770,6 +8770,12 @@ cs->halted = !cpu_is_bsp(cpu); +#if defined(CONFIG_IGVM) + if (cpu_is_bsp(cpu)) { + qigvm_x86_bsp_reset(env); + } +#endif + if (kvm_enabled()) { kvm_arch_reset_vcpu(cpu); }
diff --git a/target/i386/cpu.h b/target/i386/cpu.h index d0da9bf..cee1f69 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h
@@ -2868,6 +2868,9 @@ #endif +/* igvm.c */ +void qigvm_x86_bsp_reset(CPUX86State *env); + /* cpu.c */ bool cpu_is_bsp(X86CPU *cpu);
diff --git a/target/i386/igvm.c b/target/i386/igvm.c new file mode 100644 index 0000000..457c253 --- /dev/null +++ b/target/i386/igvm.c
@@ -0,0 +1,180 @@ +/* + * QEMU IGVM, support for native x86 guests + * + * Copyright (C) 2026 Red Hat + * + * Authors: + * Gerd Hoffmann <kraxel@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" + +#include "cpu.h" +#include "hw/i386/e820_memory_layout.h" +#include "system/igvm.h" + +struct IgvmNativeVpContextX64 { + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsp; + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rflags; + uint64_t idtr_base; + uint16_t idtr_limit; + uint16_t reserved[2]; + uint16_t gdtr_limit; + uint64_t gdtr_base; + + uint16_t code_selector; + uint16_t code_attributes; + uint32_t code_base; + uint32_t code_limit; + + uint16_t data_selector; + uint16_t data_attributes; + uint32_t data_base; + uint32_t data_limit; + + uint64_t gs_base; + uint64_t cr0; + uint64_t cr3; + uint64_t cr4; + uint64_t efer; +}; + +#define FLAGS_TO_SEGCACHE(flags) \ + (((unsigned int)flags) << 8) + +static void qigvm_x86_load_context(struct IgvmNativeVpContextX64 *context, + CPUX86State *env) +{ + cpu_load_efer(env, context->efer); + cpu_x86_update_cr4(env, context->cr4); + cpu_x86_update_cr0(env, context->cr0); + cpu_x86_update_cr3(env, context->cr3); + + cpu_x86_load_seg_cache( + env, R_CS, context->code_selector, + context->code_base, context->code_limit, + FLAGS_TO_SEGCACHE(context->code_attributes)); + cpu_x86_load_seg_cache( + env, R_DS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_ES, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_FS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_GS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_SS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + + env->gdt.base = context->gdtr_base; + env->gdt.limit = context->gdtr_limit; + env->idt.base = context->idtr_base; + env->idt.limit = context->idtr_limit; + + env->regs[R_EAX] = context->rax; + env->regs[R_ECX] = context->rcx; + env->regs[R_EDX] = context->rdx; + env->regs[R_EBX] = context->rbx; + env->regs[R_ESP] = context->rsp; + env->regs[R_EBP] = context->rbp; + env->regs[R_ESI] = context->rsi; + env->regs[R_EDI] = context->rdi; +#ifdef TARGET_X86_64 + env->regs[R_R8] = context->r8; + env->regs[R_R9] = context->r9; + env->regs[R_R10] = context->r10; + env->regs[R_R11] = context->r11; + env->regs[R_R12] = context->r12; + env->regs[R_R13] = context->r13; + env->regs[R_R14] = context->r14; + env->regs[R_R15] = context->r15; +#endif + env->eip = context->rip; + env->eflags = context->rflags; +} + +/* + * convert e820 table into igvm memory map + */ +int qigvm_x86_get_mem_map_entry(int index, + ConfidentialGuestMemoryMapEntry *entry, + Error **errp) +{ + struct e820_entry *table; + int num_entries; + + num_entries = e820_get_table(&table); + if ((index < 0) || (index >= num_entries)) { + return 1; + } + entry->gpa = table[index].address; + entry->size = table[index].length; + switch (table[index].type) { + case E820_RAM: + entry->type = CGS_MEM_RAM; + break; + case E820_RESERVED: + entry->type = CGS_MEM_RESERVED; + break; + default: + /* should not happen */ + error_setg(errp, "unknown e820 type"); + return -1; + } + return 0; +} + +/* + * set initial cpu context + */ +static struct IgvmNativeVpContextX64 *bsp_context; + +int qigvm_x86_set_vp_context(void *data, int index, Error **errp) +{ + if (index != 0) { + error_setg(errp, "context can be set for BSP only"); + return -1; + } + + if (bsp_context == NULL) { + bsp_context = g_new0(struct IgvmNativeVpContextX64, 1); + } + memcpy(bsp_context, data, sizeof(struct IgvmNativeVpContextX64)); + return 0; +} + +void qigvm_x86_bsp_reset(CPUX86State *env) +{ + if (bsp_context == NULL) { + return; + } + + qigvm_x86_load_context(bsp_context, env); +}
diff --git a/target/i386/meson.build b/target/i386/meson.build index 89ba491..d385eaf 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build
@@ -26,6 +26,9 @@ )) i386_system_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-system-stub.c')) +if igvm.found() + i386_system_ss.add(files('igvm.c')) +endif i386_user_ss = ss.source_set()
diff --git a/target/rx/helper.c b/target/rx/helper.c index ef47e32..e9a7aaf 100644 --- a/target/rx/helper.c +++ b/target/rx/helper.c
@@ -41,11 +41,9 @@ env->psw_c = FIELD_EX32(psw, PSW, C); } -#define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR) void rx_cpu_do_interrupt(CPUState *cs) { CPURXState *env = cpu_env(cs); - int do_irq = cpu_test_interrupt(cs, INT_FLAGS); uint32_t save_psw; uint64_t last_pc = env->pc; @@ -59,29 +57,26 @@ save_psw = rx_cpu_pack_psw(env); env->psw_pm = env->psw_i = env->psw_u = 0; - if (do_irq) { - if (do_irq & CPU_INTERRUPT_FIR) { - env->bpc = env->pc; - env->bpsw = save_psw; - env->pc = env->fintv; - env->psw_ipl = 15; - cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR); - qemu_set_irq(env->ack, env->ack_irq); - qemu_plugin_vcpu_interrupt_cb(cs, last_pc); - qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n"); - } else if (do_irq & CPU_INTERRUPT_HARD) { - env->isp -= 4; - cpu_stl_data(env, env->isp, save_psw); - env->isp -= 4; - cpu_stl_data(env, env->isp, env->pc); - env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4); - env->psw_ipl = env->ack_ipl; - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - qemu_set_irq(env->ack, env->ack_irq); - qemu_plugin_vcpu_interrupt_cb(cs, last_pc); - qemu_log_mask(CPU_LOG_INT, - "interrupt 0x%02x raised\n", env->ack_irq); - } + if (cpu_test_interrupt(cs, CPU_INTERRUPT_FIR)) { + env->bpc = env->pc; + env->bpsw = save_psw; + env->pc = env->fintv; + env->psw_ipl = 15; + cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR); + qemu_set_irq(env->ack, env->ack_irq); + qemu_plugin_vcpu_interrupt_cb(cs, last_pc); + qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n"); + } else if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD)) { + env->isp -= 4; + cpu_stl_data(env, env->isp, save_psw); + env->isp -= 4; + cpu_stl_data(env, env->isp, env->pc); + env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4); + env->psw_ipl = env->ack_ipl; + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + qemu_set_irq(env->ack, env->ack_irq); + qemu_plugin_vcpu_interrupt_cb(cs, last_pc); + qemu_log_mask(CPU_LOG_INT, "interrupt 0x%02x raised\n", env->ack_irq); } else { uint32_t vec = cs->exception_index; const char *expname = "unknown exception";
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index f1acb16..24675fc 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c
@@ -1959,6 +1959,10 @@ if (env->cregs[i] != val && i >= 9 && i <= 11) { PERchanged = true; } + if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val & CR0_CKC_SC)) { + BQL_LOCK_GUARD(); + tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL); + } env->cregs[i] = val; HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", i, src, val); @@ -1989,10 +1993,15 @@ for (i = r1;; i = (i + 1) % 16) { uint32_t val = cpu_ldl_data_ra(env, src, ra); + uint64_t val64 = deposit64(env->cregs[i], 0, 32, val); if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) { PERchanged = true; } - env->cregs[i] = deposit64(env->cregs[i], 0, 32, val); + if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val64 & CR0_CKC_SC)) { + BQL_LOCK_GUARD(); + tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL); + } + env->cregs[i] = val64; HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val); src += sizeof(uint32_t);
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index 6d9d601..215b5b9 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c
@@ -199,11 +199,15 @@ return; } - /* difference between origins */ - time = env->ckc - td->base.low; + if (env->ckc < td->base.low) { + time = 0; + } else { + /* difference between origins */ + time = env->ckc - td->base.low; - /* nanoseconds */ - time = tod2time(time); + /* nanoseconds */ + time = tod2time(time); + } timer_mod(env->tod_timer, time); }
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index ec9e5a0..4d2b8c5 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c
@@ -5613,6 +5613,7 @@ int r2 = get_field(s, r2); if (r2 != 0) { o->in2 = load_reg(r2); + gen_addi_and_wrap_i64(s, o->in2, o->in2, 0); } } #define SPEC_in2_r2_nz 0 @@ -6379,10 +6380,12 @@ { DisasContext *dc = container_of(dcbase, DisasContext, base); - /* 31-bit mode */ - if (!(dc->base.tb->flags & FLAG_MASK_64)) { - dc->base.pc_first &= 0x7fffffff; - dc->base.pc_next = dc->base.pc_first; + if (dc->base.tb->flags & FLAG_MASK_32) { + if (!(dc->base.tb->flags & FLAG_MASK_64)) { + assert(!(dc->base.pc_first & ~((1ULL << 31) - 1))); + } + } else { + assert(!(dc->base.pc_first & ~((1ULL << 24) - 1))); } dc->cc_op = CC_OP_DYNAMIC;
diff --git a/tests/functional/arm/test_aspeed_ast1030.py b/tests/functional/arm/test_aspeed_ast1030.py index 60e2b02..d1822ed 100755 --- a/tests/functional/arm/test_aspeed_ast1030.py +++ b/tests/functional/arm/test_aspeed_ast1030.py
@@ -6,9 +6,8 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import LinuxKernelTest, Asset from aspeed import AspeedTest -from qemu_test import exec_command_and_wait_for_pattern +from qemu_test import Asset, exec_command_and_wait_for_pattern class AST1030Machine(AspeedTest):
diff --git a/tests/functional/migration.py b/tests/functional/migration.py index 0739554..2bfb1f7 100644 --- a/tests/functional/migration.py +++ b/tests/functional/migration.py
@@ -30,11 +30,11 @@ def assert_migration(self, src_vm, dst_vm): end = time.monotonic() + self.timeout while time.monotonic() < end and not self.migration_finished(src_vm): - time.sleep(0.1) + time.sleep(0.1) end = time.monotonic() + self.timeout while time.monotonic() < end and not self.migration_finished(dst_vm): - time.sleep(0.1) + time.sleep(0.1) self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed') self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed')
diff --git a/tests/functional/ppc/test_74xx.py b/tests/functional/ppc/test_74xx.py index 5386016..219c799 100755 --- a/tests/functional/ppc/test_74xx.py +++ b/tests/functional/ppc/test_74xx.py
@@ -10,7 +10,7 @@ from qemu_test import QemuSystemTest from qemu_test import wait_for_console_pattern -class ppc74xxCpu(QemuSystemTest): +class Ppc74xxCpu(QemuSystemTest): timeout = 5
diff --git a/tests/functional/ppc/test_sam460ex.py b/tests/functional/ppc/test_sam460ex.py index 31cf9dd..024406d 100755 --- a/tests/functional/ppc/test_sam460ex.py +++ b/tests/functional/ppc/test_sam460ex.py
@@ -8,10 +8,11 @@ from qemu_test import exec_command_and_wait_for_pattern -class sam460exTest(LinuxKernelTest): +class Sam460exTest(LinuxKernelTest): ASSET_BR2_SAM460EX_LINUX = Asset( - 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux', + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main' + '/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'), '6f46346f3e20e8b5fc050ff363f350f8b9d76a051b9e0bd7ea470cc680c14df2') def test_ppc_sam460ex_buildroot(self):
diff --git a/tests/functional/ppc64/test_mac99.py b/tests/functional/ppc64/test_mac99.py index dfd9c01..a3261a8 100755 --- a/tests/functional/ppc64/test_mac99.py +++ b/tests/functional/ppc64/test_mac99.py
@@ -7,14 +7,16 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern -class mac99Test(LinuxKernelTest): +class Mac99Test(LinuxKernelTest): ASSET_BR2_MAC99_LINUX = Asset( - 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux', + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main' + '/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'), 'd59307437e4365f2cced0bbd1b04949f7397b282ef349b7cafd894d74aadfbff') ASSET_BR2_MAC99_ROOTFS = Asset( - 'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main//buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2', + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main' + '/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2'), 'bbd5fd8af62f580bc4e585f326fe584e22856572633a8333178ea6d4ed4955a4') def test_ppc64_mac99_buildroot(self):
diff --git a/tests/functional/ppc64/test_powernv.py b/tests/functional/ppc64/test_powernv.py index 9ada832..0ea6c93 100755 --- a/tests/functional/ppc64/test_powernv.py +++ b/tests/functional/ppc64/test_powernv.py
@@ -10,7 +10,7 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import wait_for_console_pattern -class powernvMachine(LinuxKernelTest): +class PowernvMachine(LinuxKernelTest): timeout = 90 KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
diff --git a/tests/functional/ppc64/test_pseries.py b/tests/functional/ppc64/test_pseries.py index 6705793..7840c4e 100755 --- a/tests/functional/ppc64/test_pseries.py +++ b/tests/functional/ppc64/test_pseries.py
@@ -10,7 +10,7 @@ from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern -class pseriesMachine(QemuSystemTest): +class PseriesMachine(QemuSystemTest): timeout = 90 KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
diff --git a/tests/functional/ppc64/test_reverse_debug.py b/tests/functional/ppc64/test_reverse_debug.py index 69551fb..4eef779 100755 --- a/tests/functional/ppc64/test_reverse_debug.py +++ b/tests/functional/ppc64/test_reverse_debug.py
@@ -18,7 +18,7 @@ from reverse_debugging import ReverseDebugging -class ReverseDebugging_ppc64(ReverseDebugging): +class ReverseDebuggingPpc64(ReverseDebugging): @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992") def test_ppc64_pseries(self):
diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index ab3a7bb..bae4076 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py
@@ -112,7 +112,7 @@ def _wait_for_other_download(self, tmp_cache_file): return False self.log.debug("Time out while waiting for %s!", tmp_cache_file) - raise + raise TimeoutError(f"Time out while waiting for {tmp_cache_file}") def _save_time_stamp(self): ''' @@ -141,7 +141,7 @@ def fetch(self): self.log.info("Downloading %s to %s...", self.url, self.cache_file) tmp_cache_file = self.cache_file.with_suffix(".download") - for retries in range(3): + for _retries in range(3): try: with tmp_cache_file.open("xb") as dst: with urllib.request.urlopen(self.url) as resp: @@ -181,7 +181,7 @@ def fetch(self): # server or networking problem if e.code == 404: raise AssetError(self, "Unable to download: " - "HTTP error %d" % e.code) + "HTTP error %d" % e.code) from e continue except URLError as e: # This is typically a network/service level error @@ -190,7 +190,7 @@ def fetch(self): self.log.error("Unable to download %s: URL error %s", self.url, e.reason) raise AssetError(self, "Unable to download: URL error %s" % - e.reason, transient=True) + e.reason, transient=True) from e except ConnectionError as e: # A socket connection failure, such as dropped conn # or refused conn @@ -201,7 +201,7 @@ def fetch(self): except Exception as e: tmp_cache_file.unlink() raise AssetError(self, "Unable to download: %s" % e, - transient=True) + transient=True) from e if not os.path.exists(tmp_cache_file): raise AssetError(self, "Download retries exceeded", transient=True) @@ -214,7 +214,6 @@ def fetch(self): self.hash.encode('utf8')) except Exception as e: self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file, e) - pass if not self._check(tmp_cache_file): tmp_cache_file.unlink() @@ -224,9 +223,10 @@ def fetch(self): # Remove write perms to stop tests accidentally modifying them os.chmod(self.cache_file, stat.S_IRUSR | stat.S_IRGRP) - self.log.info("Cached %s at %s" % (self.url, self.cache_file)) + self.log.info("Cached %s at %s", self.url, self.cache_file) return str(self.cache_file) + @staticmethod def precache_test(test): log = logging.getLogger('qemu-test') log.setLevel(logging.DEBUG) @@ -237,16 +237,17 @@ def precache_test(test): handler.setFormatter(formatter) log.addHandler(handler) for name, asset in vars(test.__class__).items(): - if name.startswith("ASSET_") and type(asset) == Asset: + if name.startswith("ASSET_") and isinstance(asset, Asset): try: asset.fetch() except AssetError as e: if not e.transient: raise - log.error("%s: skipping asset precache" % e) + log.error("%s: skipping asset precache", e) log.removeHandler(handler) + @staticmethod def precache_suite(suite): for test in suite: if isinstance(test, unittest.TestSuite): @@ -254,9 +255,10 @@ def precache_suite(suite): elif isinstance(test, unittest.TestCase): Asset.precache_test(test) - def precache_suites(path, cacheTstamp): + @staticmethod + def precache_suites(path, cache_tstamp): loader = unittest.loader.defaultTestLoader tests = loader.loadTestsFromNames([path], None) - with open(cacheTstamp, "w") as fh: + with open(cache_tstamp, "w", encoding='utf-8'): Asset.precache_suite(tests)
diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py index b239295..8074183 100644 --- a/tests/functional/qemu_test/decorators.py +++ b/tests/functional/qemu_test/decorators.py
@@ -10,136 +10,134 @@ from .cmd import which -''' -Decorator to skip execution of a test if the provided -environment variables are not set. -Example: - @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1") -''' def skipIfMissingEnv(*vars_): + ''' + Decorator to skip execution of a test if the provided + environment variables are not set. + Example: + + @skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1") + ''' missing_vars = [] for var in vars_: - if os.getenv(var) == None: + if os.getenv(var) is None: missing_vars.append(var) - has_vars = True if len(missing_vars) == 0 else False + has_vars = len(missing_vars) == 0 return skipUnless(has_vars, f"Missing env var(s): {', '.join(missing_vars)}") -''' - -Decorator to skip execution of a test if the list -of command binaries is not available in $PATH. -Example: - - @skipIfMissingCommands("mkisofs", "losetup") -''' def skipIfMissingCommands(*args): + ''' + Decorator to skip execution of a test if the list + of command binaries is not available in $PATH. + Example: + + @skipIfMissingCommands("mkisofs", "losetup") + ''' has_cmds = True for cmd in args: - if not which(cmd): - has_cmds = False - break + if not which(cmd): + has_cmds = False + break return skipUnless(has_cmds, 'required command(s) "%s" not installed' % ", ".join(args)) -''' -Decorator to skip execution of a test if the current -host operating system does match one of the prohibited -ones. -Example - - @skipIfOperatingSystem("Linux", "Darwin") -''' def skipIfOperatingSystem(*args): + ''' + Decorator to skip execution of a test if the current host + operating system does match one of the prohibited ones. + Example: + + @skipIfOperatingSystem("Linux", "Darwin") + ''' return skipIf(platform.system() in args, 'running on an OS (%s) that is not able to run this test' % ", ".join(args)) -''' -Decorator to skip execution of a test if the current -host machine does not match one of the permitted -machines. -Example - - @skipIfNotMachine("x86_64", "aarch64") -''' def skipIfNotMachine(*args): + ''' + Decorator to skip execution of a test if the current + host machine does not match one of the permitted machines. + Example: + + @skipIfNotMachine("x86_64", "aarch64") + ''' return skipUnless(platform.machine() in args, 'not running on one of the required machine(s) "%s"' % ", ".join(args)) -''' -Decorator to skip execution of flaky tests, unless -the $QEMU_TEST_FLAKY_TESTS environment variable is set. -A bug URL must be provided that documents the observed -failure behaviour, so it can be tracked & re-evaluated -in future. - -Historical tests may be providing "None" as the bug_url -but this should not be done for new test. - -Example: - - @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN") -''' def skipFlakyTest(bug_url): + ''' + Decorator to skip execution of flaky tests, unless + the $QEMU_TEST_FLAKY_TESTS environment variable is set. + A bug URL must be provided that documents the observed + failure behaviour, so it can be tracked & re-evaluated + in future. + + Historical tests may be providing "None" as the bug_url + but this should not be done for new test. + + Example: + + @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN") + ''' if bug_url is None: bug_url = "FIXME: reproduce flaky test and file bug report or remove" return skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), f'Test is unstable: {bug_url}') -''' -Decorator to skip execution of tests which are likely -to execute untrusted commands on the host, or commands -which process untrusted code, unless the -$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set. -Example: - - @skipUntrustedTest() -''' def skipUntrustedTest(): + ''' + Decorator to skip execution of tests which are likely + to execute untrusted commands on the host, or commands + which process untrusted code, unless the + $QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set. + Example: + + @skipUntrustedTest() + ''' return skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'Test runs untrusted code / processes untrusted data') -''' -Decorator to skip execution of tests which need large -data storage (over around 500MB-1GB mark) on the host, -unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment -variable is set - -Example: - - @skipBigDataTest() -''' def skipBigDataTest(): + ''' + Decorator to skip execution of tests which need large + data storage (over around 500MB-1GB mark) on the host, + unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment + variable is set + + Example: + + @skipBigDataTest() + ''' return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'Test requires large host storage space') -''' -Decorator to skip execution of tests which have a really long -runtime (and might e.g. time out if QEMU has been compiled with -debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW -environment variable is set - -Example: - - @skipSlowTest() -''' def skipSlowTest(): + ''' + Decorator to skip execution of tests which have a really long + runtime (and might e.g. time out if QEMU has been compiled with + debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW + environment variable is set + + Example: + + @skipSlowTest() + ''' return skipUnless(os.getenv('QEMU_TEST_ALLOW_SLOW'), 'Test has a very long runtime and might time out') -''' -Decorator to skip execution of a test if the list -of python imports is not available. -Example: - - @skipIfMissingImports("numpy", "cv2") -''' def skipIfMissingImports(*args): + ''' + Decorator to skip execution of a test if the list + of python imports is not available. + Example: + + @skipIfMissingImports("numpy", "cv2") + ''' has_imports = True for impname in args: try: @@ -151,15 +149,15 @@ def skipIfMissingImports(*args): return skipUnless(has_imports, 'required import(s) "%s" not installed' % ", ".join(args)) -''' -Decorator to skip execution of a test if the system's -locked memory limit is below the required threshold. -Takes required locked memory threshold in kB. -Example: - - @skipLockedMemoryTest(2_097_152) -''' def skipLockedMemoryTest(locked_memory): + ''' + Decorator to skip execution of a test if the system's + locked memory limit is below the required threshold. + Takes required locked memory threshold in kB. + Example: + + @skipLockedMemoryTest(2_097_152) + ''' # get memlock hard limit in bytes _, ulimit_memory = resource.getrlimit(resource.RLIMIT_MEMLOCK)
diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py index c476752..eb10a81 100644 --- a/tests/functional/qemu_test/linuxkernel.py +++ b/tests/functional/qemu_test/linuxkernel.py
@@ -83,12 +83,12 @@ def launch_kernel(self, kernel, initrd=None, dtb=None, console_index=0, self.vm.set_console(console_index=console_index) self.vm.add_args('-kernel', kernel) if initrd: - self.vm.add_args('-initrd', initrd) + self.vm.add_args('-initrd', initrd) if dtb: - self.vm.add_args('-dtb', dtb) + self.vm.add_args('-dtb', dtb) self.vm.launch() if wait_for: - self.wait_for_console_pattern(wait_for) + self.wait_for_console_pattern(wait_for) def check_http_download(self, filename, hashsum, guestport=8080, pythoncmd='python3 -m http.server'):
diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 2c0abde..1d773dd 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py
@@ -217,7 +217,7 @@ def setUp(self): self._log_fh = logging.FileHandler(self.log_filename, mode='w') self._log_fh.setLevel(logging.DEBUG) fileFormatter = logging.Formatter( - '%(asctime)s - %(levelname)s: %(message)s') + '%(asctime)s - %(levelname)s: %(name)s.%(funcName)s %(message)s') self._log_fh.setFormatter(fileFormatter) self.log.addHandler(self._log_fh) @@ -225,6 +225,9 @@ def setUp(self): self.machinelog = logging.getLogger('qemu.machine') self.machinelog.setLevel(logging.DEBUG) self.machinelog.addHandler(self._log_fh) + self.qmplog = logging.getLogger('qemu.qmp') + self.qmplog.setLevel(logging.DEBUG) + self.qmplog.addHandler(self._log_fh) if not self.assets_available(): self.skipTest('One or more assets is not available') @@ -233,8 +236,9 @@ def tearDown(self): if "QEMU_TEST_KEEP_SCRATCH" not in os.environ: shutil.rmtree(self.workdir) if self.socketdir is not None: - shutil.rmtree(self.socketdir.name) + self.socketdir.cleanup() self.socketdir = None + self.qmplog.removeHandler(self._log_fh) self.machinelog.removeHandler(self._log_fh) self.log.removeHandler(self._log_fh) self._log_fh.close()
diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py index b7ef8f7..5bbdf8f 100644 --- a/tests/functional/qemu_test/uncompress.py +++ b/tests/functional/qemu_test/uncompress.py
@@ -58,20 +58,20 @@ def zstd_uncompress(zstd_path, output_path): os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR) -''' -@params compressed: filename, Asset, or file-like object to uncompress -@params uncompressed: filename to uncompress into -@params format: optional compression format (gzip, lzma) - -Uncompresses @compressed into @uncompressed - -If @format is None, heuristics will be applied to guess the format -from the filename or Asset URL. @format must be non-None if @uncompressed -is a file-like object. - -Returns the fully qualified path to the uncompessed file -''' def uncompress(compressed, uncompressed, format=None): + ''' + @params compressed: filename, Asset, or file-like object to uncompress + @params uncompressed: filename to uncompress into + @params format: optional compression format (gzip, lzma) + + Uncompresses @compressed into @uncompressed + + If @format is None, heuristics will be applied to guess the + format from the filename or Asset URL. @format must be non-None + if @uncompressed is a file-like object. + + Returns the fully qualified path to the uncompessed file + ''' if format is None: format = guess_uncompress_format(compressed) @@ -84,19 +84,19 @@ def uncompress(compressed, uncompressed, format=None): else: raise Exception(f"Unknown compression format {format}") -''' -@params compressed: filename, Asset, or file-like object to guess - -Guess the format of @compressed, raising an exception if -no format can be determined -''' def guess_uncompress_format(compressed): - if type(compressed) == Asset: + ''' + @params compressed: filename, Asset, or file-like object to guess + + Guess the format of @compressed, raising an exception if + no format can be determined + ''' + if isinstance(compressed, Asset): compressed = urlparse(compressed.url).path - elif type(compressed) != str: + elif not isinstance(compressed, str): raise Exception(f"Unable to guess compression cformat for {compressed}") - (name, ext) = os.path.splitext(compressed) + (_name, ext) = os.path.splitext(compressed) if ext == ".xz": return "xz" elif ext == ".gz":
diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py index e7c8de8..826c267 100644 --- a/tests/functional/qemu_test/utils.py +++ b/tests/functional/qemu_test/utils.py
@@ -17,10 +17,10 @@ def get_usernet_hostfwd_port(vm): res = vm.cmd('human-monitor-command', command_line='info usernet') return get_info_usernet_hostfwd_port(res) -""" -Round up to next power of 2 -""" def pow2ceil(x): + """ + Round up to next power of 2 + """ return 1 if x == 0 else 2**(x - 1).bit_length() def file_truncate(path, size): @@ -28,12 +28,12 @@ def file_truncate(path, size): with open(path, 'ab+') as fd: fd.truncate(size) -""" -Expand file size to next power of 2 -""" def image_pow2ceil_expand(path): - size = os.path.getsize(path) - size_aligned = pow2ceil(size) - if size != size_aligned: - with open(path, 'ab+') as fd: - fd.truncate(size_aligned) + """ + Expand file size to next power of 2 + """ + size = os.path.getsize(path) + size_aligned = pow2ceil(size) + if size != size_aligned: + with open(path, 'ab+') as fd: + fd.truncate(size_aligned)
diff --git a/tests/functional/rx/test_gdbsim.py b/tests/functional/rx/test_gdbsim.py index 4924579..d31f9a4 100755 --- a/tests/functional/rx/test_gdbsim.py +++ b/tests/functional/rx/test_gdbsim.py
@@ -17,9 +17,6 @@ class RxGdbSimMachine(QemuSystemTest): - timeout = 30 - KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' - ASSET_UBOOT = Asset( ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' 'u-boot.bin'), @@ -47,7 +44,7 @@ def test_uboot(self): self.vm.launch() uboot_version = 'U-Boot 2016.05-rc3-23705-ga1ef3c71cb-dirty' wait_for_console_pattern(self, uboot_version) - gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)' + #gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)' # FIXME limit baudrate on chardev, else we type too fast # https://gitlab.com/qemu-project/qemu/-/issues/2691 #exec_command_and_wait_for_pattern(self, 'version', gcc_version) @@ -63,7 +60,6 @@ def test_linux_sash(self): kernel_path = self.ASSET_KERNEL.fetch() self.vm.set_console() - kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'earlycon' self.vm.add_args('-kernel', kernel_path, '-dtb', dtb_path, '-no-reboot')
diff --git a/tests/functional/x86_64/test_acpi_bits.py b/tests/functional/x86_64/test_acpi_bits.py index 9a28165..ec716d6 100755 --- a/tests/functional/x86_64/test_acpi_bits.py +++ b/tests/functional/x86_64/test_acpi_bits.py
@@ -57,6 +57,7 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods """ def __init__(self, binary: str, + *, args: Sequence[str] = (), wrapper: Sequence[str] = (), name: Optional[str] = None, @@ -225,7 +226,7 @@ def generate_bits_iso(self): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True) - self.log.info("grub-mkrescue output %s" % proc.stdout) + self.log.info("grub-mkrescue output %s", proc.stdout) else: subprocess.check_call([mkrescue_script, '-o', iso_file, bits_dir], @@ -287,9 +288,8 @@ def parse_log(self): except AssertionError as e: self._print_log(log) raise e - else: - if os.getenv('V') or os.getenv('BITS_DEBUG'): - self._print_log(log) + if os.getenv('V') or os.getenv('BITS_DEBUG'): + self._print_log(log) def tearDown(self): """
diff --git a/tests/functional/x86_64/test_virtio_balloon.py b/tests/functional/x86_64/test_virtio_balloon.py index 5877b6c..7a579e0 100755 --- a/tests/functional/x86_64/test_virtio_balloon.py +++ b/tests/functional/x86_64/test_virtio_balloon.py
@@ -66,7 +66,7 @@ def assert_initial_stats(self): when = ret.get('last-update') assert when == 0 stats = ret.get('stats') - for name, val in stats.items(): + for _name, val in stats.items(): assert val == UNSET_STATS_VALUE def assert_running_stats(self, then): @@ -87,10 +87,10 @@ def assert_running_stats(self, then): now = time.time() - assert when > then and when < now + assert now > when > then stats = ret.get('stats') # Stat we expect this particular Kernel to have set - expectData = [ + expect_data = [ "stat-available-memory", "stat-disk-caches", "stat-free-memory", @@ -103,7 +103,7 @@ def assert_running_stats(self, then): "stat-total-memory", ] for name, val in stats.items(): - if name in expectData: + if name in expect_data: assert val != UNSET_STATS_VALUE else: assert val == UNSET_STATS_VALUE
diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target index 8cd4667..a4425d3 100644 --- a/tests/tcg/s390x/Makefile.softmmu-target +++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -28,6 +28,7 @@ mc \ per \ precise-smc-softmmu \ + sckc \ ssm-early \ stosm-early \ stpq \
diff --git a/tests/tcg/s390x/sckc.S b/tests/tcg/s390x/sckc.S new file mode 100644 index 0000000..ecd64a3 --- /dev/null +++ b/tests/tcg/s390x/sckc.S
@@ -0,0 +1,63 @@ +/* + * Test clock comparator. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + .org 0x130 +ext_old_psw: + .org 0x1b0 +ext_new_psw: + .quad 0x180000000, _ext /* 64-bit mode */ + .org 0x1d0 +pgm_new_psw: + .quad 0x2000000000000,0 /* disabled wait */ + .org 0x200 /* lowcore padding */ + + .globl _start +_start: + lpswe start31_psw +_start31: + stctg %c0,%c0,c0 + oi c0+6,8 /* set clock-comparator subclass mask */ + lctlg %c0,%c0,c0 + +0: + brasl %r14,_f /* %r14's most significant bit is 1 */ + jg 0b +_f: + br %r14 /* it must not end up in ext_old_psw */ + +_ext: + stg %r0,ext_saved_r0 + + lg %r0,ext_counter + aghi %r0,1 + stg %r0,ext_counter + + cgfi %r0,0x1000 + jnz 0f + lpswe success_psw +0: + + stck clock + lg %r0,clock + agfi %r0,0x40000 /* 64us * 0x1000 =~ 0.25s */ + stg %r0,clock + sckc clock + + lg %r0,ext_saved_r0 + lpswe ext_old_psw + + .align 8 +start31_psw: + .quad 0x100000080000000,_start31 /* EX, 31-bit mode */ +success_psw: + .quad 0x2000000000000,0xfff /* see is_special_wait_psw() */ +c0: + .skip 8 +clock: + .quad 0 +ext_counter: + .quad 0 +ext_saved_r0: + .skip 8
diff --git a/tests/unit/test-aio-multithread.c b/tests/unit/test-aio-multithread.c index 0ead6bf..c24200a 100644 --- a/tests/unit/test-aio-multithread.c +++ b/tests/unit/test-aio-multithread.c
@@ -443,7 +443,7 @@ int main(int argc, char **argv) { - init_clocks(NULL); + qemu_init_clocks(NULL); g_test_init(&argc, &argv, NULL); g_test_add_func("/aio/multi/lifecycle", test_lifecycle);
diff --git a/util/hexdump.c b/util/hexdump.c index f29ffce..7cfc547 100644 --- a/util/hexdump.c +++ b/util/hexdump.c
@@ -22,6 +22,19 @@ return (x < 10 ? '0' : 'a' - 10) + x; } +static size_t hexdump_line_length(size_t buf_len, size_t unit_len, + size_t block_len) +{ + size_t est = buf_len * 2; + if (unit_len) { + est += buf_len / unit_len; + } + if (block_len) { + est += buf_len / block_len; + } + return est; +} + GString *qemu_hexdump_line(GString *str, const void *vbuf, size_t len, size_t unit_len, size_t block_len) { @@ -30,14 +43,8 @@ if (str == NULL) { /* Estimate the length of the output to avoid reallocs. */ - size_t est = len * 2; - if (unit_len) { - est += len / unit_len; - } - if (block_len) { - est += len / block_len; - } - str = g_string_sized_new(est + 1); + str = g_string_sized_new(hexdump_line_length(len, unit_len, block_len) + + 1); } for (u = 0, b = 0; len; u++, b++, len--, buf++) { @@ -76,13 +83,16 @@ } #define QEMU_HEXDUMP_LINE_BYTES 16 -#define QEMU_HEXDUMP_LINE_WIDTH \ - (QEMU_HEXDUMP_LINE_BYTES * 2 + QEMU_HEXDUMP_LINE_BYTES / 4) +#define QEMU_HEXDUMP_UNIT 1 +#define QEMU_HEXDUMP_BLOCK 4 void qemu_hexdump(FILE *fp, const char *prefix, const void *bufptr, size_t size) { - g_autoptr(GString) str = g_string_sized_new(QEMU_HEXDUMP_LINE_WIDTH + 1); + int width = hexdump_line_length(QEMU_HEXDUMP_LINE_BYTES, + QEMU_HEXDUMP_UNIT, + QEMU_HEXDUMP_BLOCK); + g_autoptr(GString) str = g_string_sized_new(width + 1); char ascii[QEMU_HEXDUMP_LINE_BYTES + 1]; size_t b, len; @@ -90,11 +100,11 @@ len = MIN(size - b, QEMU_HEXDUMP_LINE_BYTES); g_string_truncate(str, 0); - qemu_hexdump_line(str, bufptr + b, len, 1, 4); + qemu_hexdump_line(str, bufptr + b, len, + QEMU_HEXDUMP_UNIT, QEMU_HEXDUMP_BLOCK); asciidump_line(ascii, bufptr + b, len); - fprintf(fp, "%s: %04zx: %-*s %s\n", - prefix, b, QEMU_HEXDUMP_LINE_WIDTH, str->str, ascii); + fprintf(fp, "%s: %04zx: %-*s %s\n", prefix, b, width, str->str, ascii); } }
diff --git a/util/main-loop.c b/util/main-loop.c index b8ddda8..b462598 100644 --- a/util/main-loop.c +++ b/util/main-loop.c
@@ -162,7 +162,7 @@ int ret; GSource *src; - init_clocks(qemu_timer_notify_cb); + qemu_init_clocks(qemu_timer_notify_cb); ret = qemu_signal_init(errp); if (ret) {
diff --git a/util/qemu-thread-common.h b/util/qemu-thread-common.h index 2af6b12..0933184 100644 --- a/util/qemu-thread-common.h +++ b/util/qemu-thread-common.h
@@ -14,6 +14,7 @@ #define QEMU_THREAD_COMMON_H #include "qemu/thread.h" +#include "qemu/main-loop.h" #include "trace.h" static inline void qemu_mutex_post_init(QemuMutex *mutex) @@ -39,6 +40,9 @@ mutex->line = line; #endif trace_qemu_mutex_locked(mutex, file, line); + if (mutex_is_bql(mutex)) { + bql_update_status(true); + } } static inline void qemu_mutex_pre_unlock(QemuMutex *mutex, @@ -49,6 +53,9 @@ mutex->line = 0; #endif trace_qemu_mutex_unlock(mutex, file, line); + if (mutex_is_bql(mutex)) { + bql_update_status(false); + } } #endif
diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 56f11b6..2a6be4c 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c
@@ -637,7 +637,7 @@ return cpus_set_virtual_clock(time); } -void init_clocks(QEMUTimerListNotifyCB *notify_cb) +void qemu_init_clocks(QEMUTimerListNotifyCB *notify_cb) { QEMUClockType type; for (type = 0; type < QEMU_CLOCK_MAX; type++) {