diff options
36 files changed, 251 insertions, 83 deletions
diff --git a/docs/about/index.rst b/docs/about/index.rst index beb762a..5bea653 100644 --- a/docs/about/index.rst +++ b/docs/about/index.rst @@ -1,5 +1,6 @@ +---------- About QEMU -========== +---------- QEMU is a generic and open source machine emulator and virtualizer. diff --git a/docs/devel/code-of-conduct.rst b/docs/devel/code-of-conduct.rst index 277b525..195444d 100644 --- a/docs/devel/code-of-conduct.rst +++ b/docs/devel/code-of-conduct.rst @@ -55,6 +55,6 @@ Sources ------- This document is based on the `Fedora Code of Conduct -<https://fedoraproject.org/code-of-conduct>`__ and the -`Contributor Covenant version 1.3.0 +<http://web.archive.org/web/20210429132536/https://docs.fedoraproject.org/en-US/project/code-of-conduct/>`__ +(as of April 2021) and the `Contributor Covenant version 1.3.0 <https://www.contributor-covenant.org/version/1/3/0/code-of-conduct/>`__. diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 5522db7..f95df10 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -1,5 +1,6 @@ +--------------------- Developer Information -===================== +--------------------- This section of the manual documents various parts of the internals of QEMU. You only need to read it if you are interested in reading or diff --git a/docs/index.rst b/docs/index.rst index 5f7eaaa..0b9ee99 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,6 +3,7 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +================================ Welcome to QEMU's documentation! ================================ diff --git a/docs/interop/index.rst b/docs/interop/index.rst index f9801a9..47b9ed8 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -1,5 +1,6 @@ +------------------------------------------------ System Emulation Management and Interoperability -================================================ +------------------------------------------------ This section of the manual contains documents and specifications that are useful for making QEMU interoperate with other software. diff --git a/docs/specs/index.rst b/docs/specs/index.rst index 65e9663..ecc4389 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -1,5 +1,6 @@ +---------------------------------------------- System Emulation Guest Hardware Specifications -============================================== +---------------------------------------------- This section of the manual contains specifications of guest hardware that is specific to QEMU. diff --git a/docs/system/cpu-models-x86.rst.inc b/docs/system/cpu-models-x86.rst.inc index 9119f5d..6e8be7d 100644 --- a/docs/system/cpu-models-x86.rst.inc +++ b/docs/system/cpu-models-x86.rst.inc @@ -1,5 +1,5 @@ Recommendations for KVM CPU model configuration on x86 hosts -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +============================================================ The information that follows provides recommendations for configuring CPU models on x86 hosts. The goals are to maximise performance, while @@ -368,7 +368,7 @@ featureset, which prevents guests having optimal performance. Syntax for configuring CPU models -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +================================= The examples below illustrate the approach to configuring the various CPU models / features in QEMU and libvirt. diff --git a/docs/system/i386/cpu.rst b/docs/system/i386/cpu.rst new file mode 100644 index 0000000..738719d --- /dev/null +++ b/docs/system/i386/cpu.rst @@ -0,0 +1 @@ +.. include:: ../cpu-models-x86.rst.inc diff --git a/docs/system/index.rst b/docs/system/index.rst index 7b9276c..73bbedb 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -1,5 +1,6 @@ +---------------- System Emulation -================ +---------------- This section of the manual is the overall guide for users using QEMU for full system emulation (as opposed to user-mode emulation). diff --git a/docs/system/qemu-block-drivers.rst b/docs/system/qemu-block-drivers.rst index bd99d4f..c2c0114 100644 --- a/docs/system/qemu-block-drivers.rst +++ b/docs/system/qemu-block-drivers.rst @@ -1,18 +1,22 @@ :orphan: +============================ QEMU block drivers reference ============================ +-------- Synopsis -------- QEMU block driver reference manual +----------- Description ----------- .. include:: qemu-block-drivers.rst.inc +-------- See also -------- diff --git a/docs/system/qemu-cpu-models.rst b/docs/system/qemu-cpu-models.rst index 53d7538..5cf6e46 100644 --- a/docs/system/qemu-cpu-models.rst +++ b/docs/system/qemu-cpu-models.rst @@ -1,20 +1,24 @@ :orphan: +================================== QEMU / KVM CPU model configuration ================================== +-------- Synopsis -'''''''' +-------- QEMU CPU Modelling Infrastructure manual +----------- Description -''''''''''' +----------- .. include:: cpu-models-x86.rst.inc .. include:: cpu-models-mips.rst.inc +-------- See also -'''''''' +-------- The HTML documentation of QEMU for more precise information and Linux user mode emulator invocation. diff --git a/docs/system/qemu-manpage.rst b/docs/system/qemu-manpage.rst index e9a25d0..c47a412 100644 --- a/docs/system/qemu-manpage.rst +++ b/docs/system/qemu-manpage.rst @@ -6,9 +6,11 @@ parts of the documentation that go in the manpage as well as the HTML manual. -Title -===== +======================= +QEMU User Documentation +======================= +-------- Synopsis -------- @@ -16,11 +18,13 @@ Synopsis |qemu_system| [options] [disk_image] +----------- Description ----------- .. include:: target-i386-desc.rst.inc +------- Options ------- @@ -33,11 +37,13 @@ not need a disk image. .. include:: mux-chardev.rst.inc +----- Notes ----- .. include:: device-url-syntax.rst.inc +-------- See also -------- diff --git a/docs/system/target-i386.rst b/docs/system/target-i386.rst index 22ba5ce..c9720a8 100644 --- a/docs/system/target-i386.rst +++ b/docs/system/target-i386.rst @@ -19,7 +19,13 @@ Board-specific documentation i386/microvm i386/pc -.. include:: cpu-models-x86.rst.inc +Architectural features +~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + i386/cpu .. _pcsys_005freq: diff --git a/docs/tools/index.rst b/docs/tools/index.rst index ef6041a..1edd5a8 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -1,5 +1,6 @@ +----- Tools -===== +----- This section of the manual documents QEMU's "tools": its command line utilities and other standalone programs. diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index b7d602a..fe6c30d 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -1,3 +1,4 @@ +======================= QEMU disk image utility ======================= diff --git a/docs/tools/qemu-nbd.rst b/docs/tools/qemu-nbd.rst index ee862fa..e39a9f4 100644 --- a/docs/tools/qemu-nbd.rst +++ b/docs/tools/qemu-nbd.rst @@ -1,3 +1,4 @@ +===================================== QEMU Disk Network Block Device Server ===================================== diff --git a/docs/tools/qemu-pr-helper.rst b/docs/tools/qemu-pr-helper.rst index ac03618..eaebe40 100644 --- a/docs/tools/qemu-pr-helper.rst +++ b/docs/tools/qemu-pr-helper.rst @@ -1,3 +1,4 @@ +================================== QEMU persistent reservation helper ================================== diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst index 3ec4bdd..b8ef448 100644 --- a/docs/tools/qemu-storage-daemon.rst +++ b/docs/tools/qemu-storage-daemon.rst @@ -1,3 +1,4 @@ +=================== QEMU Storage Daemon =================== diff --git a/docs/tools/qemu-trace-stap.rst b/docs/tools/qemu-trace-stap.rst index fb70445..d53073b 100644 --- a/docs/tools/qemu-trace-stap.rst +++ b/docs/tools/qemu-trace-stap.rst @@ -1,3 +1,4 @@ +========================= QEMU SystemTap trace tool ========================= diff --git a/docs/user/index.rst b/docs/user/index.rst index 9faa4ba..2c4e29f 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -1,5 +1,6 @@ +------------------- User Mode Emulation -=================== +------------------- This section of the manual is the overall guide for users using QEMU for user-mode emulation. In this mode, QEMU can launch diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 9b8dcca..c06b30d 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -878,6 +878,7 @@ static struct { { "etc/tpm/log", 150 }, { "etc/acpi/rsdp", 160 }, { "bootorder", 170 }, + { "etc/msr_feature_control", 180 }, #define FW_CFG_ORDER_OVERRIDE_LAST 200 }; diff --git a/include/sysemu/nvmm.h b/include/sysemu/nvmm.h index 6d21659..833670f 100644 --- a/include/sysemu/nvmm.h +++ b/include/sysemu/nvmm.h @@ -10,8 +10,7 @@ #ifndef QEMU_NVMM_H #define QEMU_NVMM_H -#include "config-host.h" -#include "qemu-common.h" +#ifdef NEED_CPU_H #ifdef CONFIG_NVMM @@ -23,4 +22,6 @@ int nvmm_enabled(void); #endif /* CONFIG_NVMM */ -#endif /* CONFIG_NVMM */ +#endif /* NEED_CPU_H */ + +#endif /* QEMU_NVMM_H */ diff --git a/meson.build b/meson.build index 9a64d16..7d7d14a 100644 --- a/meson.build +++ b/meson.build @@ -931,7 +931,7 @@ vnc = not_found png = not_found jpeg = not_found sasl = not_found -if not get_option('vnc').disabled() +if have_system and not get_option('vnc').disabled() vnc = declare_dependency() # dummy dependency png = dependency('libpng', required: get_option('vnc_png'), method: 'pkg-config', kwargs: static_kwargs) diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build index 05eda6c..44247a1 100644 --- a/pc-bios/keymaps/meson.build +++ b/pc-bios/keymaps/meson.build @@ -38,6 +38,7 @@ if meson.is_cross_build() or 'CONFIG_XKBCOMMON' not in config_host else native_qemu_keymap = qemu_keymap endif +cp = find_program('cp') t = [] foreach km, args: keymaps @@ -55,7 +56,7 @@ foreach km, args: keymaps build_by_default: true, input: km, output: km, - command: ['cp', '@INPUT@', '@OUTPUT@'], + command: [cp, '@INPUT@', '@OUTPUT@'], install: true, install_dir: qemu_datadir / 'keymaps') endif diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 97e250e..6b029f1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -631,7 +631,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) #define TCG_EXT4_FEATURES 0 -#define TCG_SVM_FEATURES CPUID_SVM_NPT +#define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | \ + CPUID_SVM_SVME_ADDR_CHK) #define TCG_KVM_FEATURES 0 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \ CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ @@ -5115,6 +5116,15 @@ static void x86_register_cpudef_types(const X86CPUDefinition *def) } +uint32_t cpu_x86_virtual_addr_width(CPUX86State *env) +{ + if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_LA57) { + return 57; /* 57 bits virtual */ + } else { + return 48; /* 48 bits virtual */ + } +} + void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -5517,16 +5527,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0x80000008: /* virtual & phys address size in low 2 bytes. */ + *eax = cpu->phys_bits; if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { /* 64 bit processor */ - *eax = cpu->phys_bits; /* configurable physical bits */ - if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_LA57) { - *eax |= 0x00003900; /* 57 bits virtual */ - } else { - *eax |= 0x00003000; /* 48 bits virtual */ - } - } else { - *eax = cpu->phys_bits; + *eax |= (cpu_x86_virtual_addr_width(env) << 8); } *ebx = env->features[FEAT_8000_0008_EBX]; if (cs->nr_cores * cs->nr_threads > 1) { @@ -5651,8 +5655,9 @@ static void x86_cpu_reset(DeviceState *dev) env->old_exception = -1; /* init to reset state */ - + env->int_ctl = 0; env->hflags2 |= HF2_GIF_MASK; + env->hflags2 |= HF2_VGIF_MASK; env->hflags &= ~HF_GUEST_MASK; cpu_x86_update_cr0(env, 0x60000010); @@ -6536,10 +6541,12 @@ int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request) !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { return CPU_INTERRUPT_HARD; #if !defined(CONFIG_USER_ONLY) - } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + } else if (env->hflags2 & HF2_VGIF_MASK) { + if((interrupt_request & CPU_INTERRUPT_VIRQ) && (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { - return CPU_INTERRUPT_VIRQ; + return CPU_INTERRUPT_VIRQ; + } #endif } } diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 6c50d3a..71ae314 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -203,6 +203,7 @@ typedef enum X86Seg { #define HF2_MPX_PR_SHIFT 5 /* BNDCFGx.BNDPRESERVE */ #define HF2_NPT_SHIFT 6 /* Nested Paging enabled */ #define HF2_IGNNE_SHIFT 7 /* Ignore CR0.NE=0 */ +#define HF2_VGIF_SHIFT 8 /* Can take VIRQ*/ #define HF2_GIF_MASK (1 << HF2_GIF_SHIFT) #define HF2_HIF_MASK (1 << HF2_HIF_SHIFT) @@ -212,6 +213,7 @@ typedef enum X86Seg { #define HF2_MPX_PR_MASK (1 << HF2_MPX_PR_SHIFT) #define HF2_NPT_MASK (1 << HF2_NPT_SHIFT) #define HF2_IGNNE_MASK (1 << HF2_IGNNE_SHIFT) +#define HF2_VGIF_MASK (1 << HF2_VGIF_SHIFT) #define CR0_PE_SHIFT 0 #define CR0_MP_SHIFT 1 @@ -257,6 +259,7 @@ typedef enum X86Seg { | CR4_DE_MASK | CR4_PSE_MASK | CR4_PAE_MASK \ | CR4_MCE_MASK | CR4_PGE_MASK | CR4_PCE_MASK \ | CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK |CR4_UMIP_MASK \ + | CR4_LA57_MASK \ | CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \ | CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK)) @@ -1577,6 +1580,7 @@ typedef struct CPUX86State { uint64_t nested_cr3; uint32_t nested_pg_mode; uint8_t v_tpr; + uint32_t int_ctl; /* KVM states, automatically cleared on reset */ uint8_t nmi_injected; @@ -1954,6 +1958,8 @@ typedef struct PropValue { } PropValue; void x86_cpu_apply_props(X86CPU *cpu, PropValue *props); +uint32_t cpu_x86_virtual_addr_width(CPUX86State *env); + /* cpu.c other functions (cpuid) */ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, @@ -2240,6 +2246,23 @@ static inline uint64_t cr4_reserved_bits(CPUX86State *env) return reserved_bits; } +static inline bool ctl_has_irq(CPUX86State *env) +{ + uint32_t int_prio; + uint32_t tpr; + + int_prio = (env->int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; + tpr = env->int_ctl & V_TPR_MASK; + + if (env->int_ctl & V_IGN_TPR_MASK) { + return (env->int_ctl & V_IRQ_MASK); + } + + return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); +} + +hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, + int *prot); #if defined(TARGET_X86_64) && \ defined(CONFIG_USER_ONLY) && \ defined(CONFIG_LINUX) diff --git a/target/i386/machine.c b/target/i386/machine.c index f6f094f..b094311 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -203,7 +203,7 @@ static int cpu_pre_save(void *opaque) X86CPU *cpu = opaque; CPUX86State *env = &cpu->env; int i; - + env->v_tpr = env->int_ctl & V_TPR_MASK; /* FPU */ env->fpus_vmstate = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; env->fptag_vmstate = 0; @@ -1356,6 +1356,25 @@ static const VMStateDescription vmstate_svm_npt = { } }; +static bool svm_guest_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return tcg_enabled() && env->int_ctl; +} + +static const VMStateDescription vmstate_svm_guest = { + .name = "cpu/svm_guest", + .version_id = 1, + .minimum_version_id = 1, + .needed = svm_guest_needed, + .fields = (VMStateField[]){ + VMSTATE_UINT32(env.int_ctl, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + #ifndef TARGET_X86_64 static bool intel_efer32_needed(void *opaque) { @@ -1524,6 +1543,7 @@ const VMStateDescription vmstate_x86_cpu = { &vmstate_msr_intel_pt, &vmstate_msr_virt_ssbd, &vmstate_svm_npt, + &vmstate_svm_guest, #ifndef TARGET_X86_64 &vmstate_efer32, #endif diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 28dee4c..a488b00 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -1132,13 +1132,14 @@ static MemoryListener nvmm_memory_listener = { }; static void -nvmm_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) +nvmm_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size) { struct nvmm_machine *mach = get_nvmm_mach(); uintptr_t hva = (uintptr_t)host; int ret; - ret = nvmm_hva_map(mach, hva, size); + ret = nvmm_hva_map(mach, hva, max_size); if (ret == -1) { error_report("NVMM: Failed to map HVA, HostVA:%p " diff --git a/target/i386/svm.h b/target/i386/svm.h index adc058d..f9a7854 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -9,6 +9,12 @@ #define V_IRQ_SHIFT 8 #define V_IRQ_MASK (1 << V_IRQ_SHIFT) +#define V_GIF_ENABLED_SHIFT 25 +#define V_GIF_ENABLED_MASK (1 << V_GIF_ENABLED_SHIFT) + +#define V_GIF_SHIFT 9 +#define V_GIF_MASK (1 << V_GIF_SHIFT) + #define V_INTR_PRIO_SHIFT 16 #define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) @@ -18,6 +24,8 @@ #define V_INTR_MASKING_SHIFT 24 #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) +#define V_VMLOAD_VMSAVE_ENABLED_MASK (1 << 1) + #define SVM_INTERRUPT_SHADOW_MASK 1 #define SVM_IOIO_STR_SHIFT 2 diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 3ed20ca..cef68b6 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -1166,7 +1166,6 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) break; #if !defined(CONFIG_USER_ONLY) case CPU_INTERRUPT_VIRQ: - /* FIXME: this should respect TPR */ cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0, 0); intno = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); @@ -1174,6 +1173,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) "Servicing virtual hardware INT=0x%02x\n", intno); do_interrupt_x86_hardirq(env, intno, 1); cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + env->int_ctl &= ~V_IRQ_MASK; break; #endif } diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index b6d940e..7af887b 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -358,7 +358,7 @@ do_check_protect_pse36: return error_code; } -static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, +hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, int *prot) { CPUX86State *env = &X86_CPU(cs)->env; diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index e7a2ebd..9ccaa05 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -73,7 +73,7 @@ target_ulong helper_read_crN(CPUX86State *env, int reg) if (!(env->hflags2 & HF2_VINTR_MASK)) { val = cpu_get_apic_tpr(env_archcpu(env)->apic_state); } else { - val = env->v_tpr; + val = env->int_ctl & V_TPR_MASK; } break; } @@ -121,7 +121,14 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0); qemu_mutex_unlock_iothread(); } - env->v_tpr = t0 & 0x0f; + env->int_ctl = (env->int_ctl & ~V_TPR_MASK) | (t0 & V_TPR_MASK); + + CPUState *cs = env_cpu(env); + if (ctl_has_irq(env)) { + cpu_interrupt(cs, CPU_INTERRUPT_VIRQ); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_VIRQ); + } break; default: env->cr[reg] = t0; diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 0d549b3..6d39611 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -41,6 +41,16 @@ static inline void svm_save_seg(CPUX86State *env, hwaddr addr, ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); } +/* + * VMRUN and VMLOAD canonicalizes (i.e., sign-extend to bit 63) all base + * addresses in the segment registers that have been loaded. + */ +static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base) +{ + uint16_t shift_amt = 64 - cpu_x86_virtual_addr_width(env); + *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt); +} + static inline void svm_load_seg(CPUX86State *env, hwaddr addr, SegmentCache *sc) { @@ -53,6 +63,7 @@ static inline void svm_load_seg(CPUX86State *env, hwaddr addr, sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit)); flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib)); sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); + svm_canonicalization(env, &sc->base); } static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, @@ -65,16 +76,6 @@ static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, sc->base, sc->limit, sc->flags); } -static inline bool ctl_has_irq(uint32_t int_ctl) -{ - uint32_t int_prio; - uint32_t tpr; - - int_prio = (int_ctl & V_INTR_PRIO_MASK) >> V_INTR_PRIO_SHIFT; - tpr = int_ctl & V_TPR_MASK; - return (int_ctl & V_IRQ_MASK) && (int_prio >= tpr); -} - static inline bool is_efer_invalid_state (CPUX86State *env) { if (!(env->efer & MSR_EFER_SVME)) { @@ -110,6 +111,39 @@ static inline bool is_efer_invalid_state (CPUX86State *env) return false; } +static inline bool virtual_gif_enabled(CPUX86State *env) +{ + if (likely(env->hflags & HF_GUEST_MASK)) { + return (env->features[FEAT_SVM] & CPUID_SVM_VGIF) + && (env->int_ctl & V_GIF_ENABLED_MASK); + } + return false; +} + +static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr) +{ + uint64_t lbr_ctl; + + if (likely(env->hflags & HF_GUEST_MASK)) { + if (likely(!(env->hflags2 & HF2_NPT_MASK)) || !(env->efer & MSR_EFER_LMA)) { + cpu_vmexit(env, exit_code, 0, retaddr); + } + + lbr_ctl = x86_ldl_phys(env_cpu(env), env->vm_vmcb + offsetof(struct vmcb, + control.lbr_ctl)); + return (env->features[FEAT_SVM] & CPUID_SVM_V_VMSAVE_VMLOAD) + && (lbr_ctl & V_VMLOAD_VMSAVE_ENABLED_MASK); + + } + + return false; +} + +static inline bool virtual_gif_set(CPUX86State *env) +{ + return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK); +} + void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -117,7 +151,6 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) target_ulong addr; uint64_t nested_ctl; uint32_t event_inj; - uint32_t int_ctl; uint32_t asid; uint64_t new_cr0; uint64_t new_cr3; @@ -245,16 +278,6 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset)); - env->gdt.base = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.gdtr.base)); - env->gdt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.gdtr.limit)); - - env->idt.base = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.idtr.base)); - env->idt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - save.idtr.limit)); - new_cr0 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr0)); if (new_cr0 & SVM_CR0_RESERVED_MASK) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); @@ -280,11 +303,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) cpu_x86_update_cr3(env, new_cr3); env->cr[2] = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr2)); - int_ctl = x86_ldl_phys(cs, + env->int_ctl = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); - if (int_ctl & V_INTR_MASKING_MASK) { - env->v_tpr = int_ctl & V_TPR_MASK; + if (env->int_ctl & V_INTR_MASKING_MASK) { env->hflags2 |= HF2_VINTR_MASK; if (env->eflags & IF_MASK) { env->hflags2 |= HF2_HIF_MASK; @@ -308,6 +330,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) R_SS); svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), R_DS); + svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr), + &env->idt); + svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr), + &env->gdt); env->eip = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip)); @@ -346,12 +372,16 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->hflags2 |= HF2_GIF_MASK; - if (ctl_has_irq(int_ctl)) { + if (ctl_has_irq(env)) { CPUState *cs = env_cpu(env); cs->interrupt_request |= CPU_INTERRUPT_VIRQ; } + if (virtual_gif_set(env)) { + env->hflags2 |= HF2_VGIF_MASK; + } + /* maybe we need to inject an event */ event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); @@ -420,6 +450,7 @@ void helper_vmload(CPUX86State *env, int aflag) { CPUState *cs = env_cpu(env); target_ulong addr; + int prot; cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); @@ -429,6 +460,10 @@ void helper_vmload(CPUX86State *env, int aflag) addr = (uint32_t)env->regs[R_EAX]; } + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) { + addr = get_hphys(cs, addr, MMU_DATA_LOAD, &prot); + } + qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb, @@ -446,6 +481,7 @@ void helper_vmload(CPUX86State *env, int aflag) env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar)); env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar)); env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask)); + svm_canonicalization(env, &env->kernelgsbase); #endif env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star)); env->sysenter_cs = x86_ldq_phys(cs, @@ -454,12 +490,14 @@ void helper_vmload(CPUX86State *env, int aflag) save.sysenter_esp)); env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip)); + } void helper_vmsave(CPUX86State *env, int aflag) { CPUState *cs = env_cpu(env); target_ulong addr; + int prot; cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); @@ -469,6 +507,10 @@ void helper_vmsave(CPUX86State *env, int aflag) addr = (uint32_t)env->regs[R_EAX]; } + if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) { + addr = get_hphys(cs, addr, MMU_DATA_STORE, &prot); + } + qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", addr, x86_ldq_phys(cs, @@ -503,13 +545,25 @@ void helper_vmsave(CPUX86State *env, int aflag) void helper_stgi(CPUX86State *env) { cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC()); - env->hflags2 |= HF2_GIF_MASK; + + if (virtual_gif_enabled(env)) { + env->int_ctl |= V_GIF_MASK; + env->hflags2 |= HF2_VGIF_MASK; + } else { + env->hflags2 |= HF2_GIF_MASK; + } } void helper_clgi(CPUX86State *env) { cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC()); - env->hflags2 &= ~HF2_GIF_MASK; + + if (virtual_gif_enabled(env)) { + env->int_ctl &= ~V_GIF_MASK; + env->hflags2 &= ~HF2_VGIF_MASK; + } else { + env->hflags2 &= ~HF2_GIF_MASK; + } } bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type) @@ -654,7 +708,6 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, void do_vmexit(CPUX86State *env) { CPUState *cs = env_cpu(env); - uint32_t int_ctl; if (env->hflags & HF_INHIBIT_IRQ_MASK) { x86_stl_phys(cs, @@ -697,16 +750,8 @@ void do_vmexit(CPUX86State *env) env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); - - int_ctl = x86_ldl_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); - int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK); - int_ctl |= env->v_tpr & V_TPR_MASK; - if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) { - int_ctl |= V_IRQ_MASK; - } x86_stl_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); + env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), env->int_ctl); x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags), cpu_compute_eflags(env)); @@ -729,6 +774,7 @@ void do_vmexit(CPUX86State *env) env->intercept = 0; env->intercept_exceptions = 0; cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + env->int_ctl = 0; env->tsc_offset = 0; env->gdt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, @@ -796,6 +842,7 @@ void do_vmexit(CPUX86State *env) env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0); env->hflags2 &= ~HF2_GIF_MASK; + env->hflags2 &= ~HF2_VGIF_MASK; /* FIXME: Resets the current ASID register to zero (host ASID). */ /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ diff --git a/trace/meson.build b/trace/meson.build index ef18f11..e401e7c 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -2,6 +2,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_files += [ trace_events_file ] @@ -39,13 +40,13 @@ foreach dir : [ '.' ] + trace_events_subdirs trace_dtrace_h = custom_target(fmt.format('trace-dtrace', 'h'), output: fmt.format('trace-dtrace', 'h'), input: trace_dtrace, - command: [ 'dtrace', '-DSTAP_SDT_V2', '-o', '@OUTPUT@', '-h', '-s', '@INPUT@' ]) + command: [ dtrace, '-DSTAP_SDT_V2', '-o', '@OUTPUT@', '-h', '-s', '@INPUT@' ]) trace_ss.add(trace_dtrace_h) if host_machine.system() != 'darwin' trace_dtrace_o = custom_target(fmt.format('trace-dtrace', 'o'), output: fmt.format('trace-dtrace', 'o'), input: trace_dtrace, - command: [ 'dtrace', '-DSTAP_SDT_V2', '-o', '@OUTPUT@', '-G', '-s', '@INPUT@' ]) + command: [ dtrace, '-DSTAP_SDT_V2', '-o', '@OUTPUT@', '-G', '-s', '@INPUT@' ]) trace_ss.add(trace_dtrace_o) endif diff --git a/ui/meson.build b/ui/meson.build index 7d25c1b..a73beb0 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -105,8 +105,6 @@ if config_host.has_key('CONFIG_SPICE') and config_host.has_key('CONFIG_GIO') ui_modules += {'spice-app': spice_ss} endif -keymap_gen = find_program('keycodemapdb/tools/keymap-gen') - keymaps = [ ['atset1', 'qcode'], ['linux', 'qcode'], @@ -134,7 +132,7 @@ if have_system or xkbcommon.found() output: output, capture: true, input: files('keycodemapdb/data/keymaps.csv'), - command: [python.full_path(), files('keycodemapdb/tools/keymap-gen'), + command: [python, files('keycodemapdb/tools/keymap-gen'), 'code-map', '--lang', 'glib2', '--varname', 'qemu_input_map_@0@_to_@1@'.format(e[0], e[1]), diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index fd9d714..6c50042 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -537,9 +537,28 @@ static void *qemu_thread_start(void *args) QEMU_TSAN_ANNOTATE_THREAD_NAME(qemu_thread_args->name); g_free(qemu_thread_args->name); g_free(qemu_thread_args); + + /* + * GCC 11 with glibc 2.17 on PowerPC reports + * + * qemu-thread-posix.c:540:5: error: ‘__sigsetjmp’ accessing 656 bytes + * in a region of size 528 [-Werror=stringop-overflow=] + * 540 | pthread_cleanup_push(qemu_thread_atexit_notify, NULL); + * | ^~~~~~~~~~~~~~~~~~~~ + * + * which is clearly nonsense. + */ +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + pthread_cleanup_push(qemu_thread_atexit_notify, NULL); r = start_routine(arg); pthread_cleanup_pop(1); + +#pragma GCC diagnostic pop + return r; } |