From 6c5f893d1771edc49fe6d3f8580be19a42b3b118 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 May 2023 17:56:33 +0200 Subject: [PATCH 01/18] build: further refine build.ninja rules In commit b0fcc6fc7fc1 ("build: rebuild build.ninja using "meson setup --reconfigure"", 2023-05-19) I changed the build.ninja rule in the Makefile to use "meson setup" so that the Makefile would pick up a changed path to the meson binary. However, there was a reason why build.ninja was rebuilt using $(NINJA) itself. Namely, ninja has its own cache of file modification times, and if it does not know about the modification that was done outside its control, it will *also* try to regenerate build.ninja. This can be simply by running "make" on a fresh tree immediately after "configure"; that will trigger an unnecessary meson run. So, apply a refinement to the rule in order to cover both cases: - track the meson binary that was used (and that is embedded in build.ninja's reconfigure rules); to do this, write build.ninja.stamp right after executing meson successfully - if it changed, force usage of "$(MESON) setup --reconfigure" to update the path in the reconfigure rule - if it didn't change, use "$(NINJA) build.ninja" just like before commit b0fcc6fc7fc1. Reported-by: Mark Cave-Ayland Tested-by: Mark Cave-Ayland Signed-off-by: Paolo Bonzini --- Makefile | 17 +++++++++++++---- configure | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b22bf6fba1..804a5681e0 100644 --- a/Makefile +++ b/Makefile @@ -83,16 +83,17 @@ config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh @if test -f meson-private/coredata.dat; then \ ./config.status --skip-meson; \ else \ - ./config.status && touch build.ninja.stamp; \ + ./config.status; \ fi # 2. meson.stamp exists if meson has run at least once (so ninja reconfigure # works), but otherwise never needs to be updated + meson-private/coredata.dat: meson.stamp meson.stamp: config-host.mak @touch meson.stamp -# 3. ensure generated build files are up-to-date +# 3. ensure meson-generated build files are up-to-date ifneq ($(NINJA),) Makefile.ninja: build.ninja @@ -106,11 +107,19 @@ Makefile.ninja: build.ninja endif ifneq ($(MESON),) -# A separate rule is needed for Makefile dependencies to avoid -n +# The path to meson always points to pyvenv/bin/meson, but the absolute +# paths could change. In that case, force a regeneration of build.ninja. +# Note that this invocation of $(NINJA), just like when Make rebuilds +# Makefiles, does not include -n. build.ninja: build.ninja.stamp $(build-files): build.ninja.stamp: meson.stamp $(build-files) - $(MESON) setup --reconfigure $(SRC_PATH) && touch $@ + @if test "$$(cat build.ninja.stamp)" = "$(MESON)" && test -n "$(NINJA)"; then \ + $(NINJA) build.ninja; \ + else \ + echo "$(MESON) setup --reconfigure $(SRC_PATH)"; \ + $(MESON) setup --reconfigure $(SRC_PATH); \ + fi && echo "$(MESON)" > $@ Makefile.mtest: build.ninja scripts/mtest2make.py $(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@ diff --git a/configure b/configure index 01a53576a7..86363a7e50 100755 --- a/configure +++ b/configure @@ -1895,6 +1895,7 @@ if test "$skip_meson" = no; then if test "$?" -ne 0 ; then error_exit "meson setup failed" fi + echo "$meson" > build.ninja.stamp else if test -f meson-private/cmd_line.txt; then # Adjust old command line options that were removed From a0488cd0444101765744b8ea848fa4af7a2e850c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 6 Jun 2023 15:49:13 +0200 Subject: [PATCH 02/18] hw/remote/proxy: Remove dubious 'event_notifier-posix.c' include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit event_notifier-posix.c is registered in meson's util_ss[] source set, which is built as libqemuutil.a.p library. Both tools and system emulation binaries are linked with qemuutil, so there is no point in including this source file. Introduced in commit bd36adb8df ("multi-process: create IOHUB object to handle irq"). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230606134913.93724-1-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- hw/remote/proxy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index 1c7786b52c..2052d721e5 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -22,7 +22,6 @@ #include "qom/object.h" #include "qemu/event_notifier.h" #include "sysemu/kvm.h" -#include "util/event_notifier-posix.c" static void probe_pci_info(PCIDevice *dev, Error **errp); static void proxy_device_reset(DeviceState *dev); From a494fdb715832000ee9047a549a35aacfea8175e Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 9 May 2023 10:27:37 +1000 Subject: [PATCH 03/18] numa: Validate cluster and NUMA node boundary if required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some architectures like ARM64, multiple CPUs in one cluster can be associated with different NUMA nodes, which is irregular configuration because we shouldn't have this in baremetal environment. The irregular configuration causes Linux guest to misbehave, as the following warning messages indicate. -smp 6,maxcpus=6,sockets=2,clusters=1,cores=3,threads=1 \ -numa node,nodeid=0,cpus=0-1,memdev=ram0 \ -numa node,nodeid=1,cpus=2-3,memdev=ram1 \ -numa node,nodeid=2,cpus=4-5,memdev=ram2 \ ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at kernel/sched/topology.c:2271 build_sched_domains+0x284/0x910 Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.14.0-268.el9.aarch64 #1 pstate: 00400005 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : build_sched_domains+0x284/0x910 lr : build_sched_domains+0x184/0x910 sp : ffff80000804bd50 x29: ffff80000804bd50 x28: 0000000000000002 x27: 0000000000000000 x26: ffff800009cf9a80 x25: 0000000000000000 x24: ffff800009cbf840 x23: ffff000080325000 x22: ffff0000005df800 x21: ffff80000a4ce508 x20: 0000000000000000 x19: ffff000080324440 x18: 0000000000000014 x17: 00000000388925c0 x16: 000000005386a066 x15: 000000009c10cc2e x14: 00000000000001c0 x13: 0000000000000001 x12: ffff00007fffb1a0 x11: ffff00007fffb180 x10: ffff80000a4ce508 x9 : 0000000000000041 x8 : ffff80000a4ce500 x7 : ffff80000a4cf920 x6 : 0000000000000001 x5 : 0000000000000001 x4 : 0000000000000007 x3 : 0000000000000002 x2 : 0000000000001000 x1 : ffff80000a4cf928 x0 : 0000000000000001 Call trace: build_sched_domains+0x284/0x910 sched_init_domains+0xac/0xe0 sched_init_smp+0x48/0xc8 kernel_init_freeable+0x140/0x1ac kernel_init+0x28/0x140 ret_from_fork+0x10/0x20 Improve the situation to warn when multiple CPUs in one cluster have been associated with different NUMA nodes. However, one NUMA node is allowed to be associated with different clusters. Signed-off-by: Gavin Shan Acked-by: Philippe Mathieu-Daudé Acked-by: Igor Mammedov Message-Id: <20230509002739.18388-2-gshan@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/hw/boards.h | 1 + 2 files changed, 43 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 1000406211..46f8f9a2b0 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1262,6 +1262,45 @@ static void machine_numa_finish_cpu_init(MachineState *machine) g_string_free(s, true); } +static void validate_cpu_cluster_to_numa_boundary(MachineState *ms) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + NumaState *state = ms->numa_state; + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); + const CPUArchId *cpus = possible_cpus->cpus; + int i, j; + + if (state->num_nodes <= 1 || possible_cpus->len <= 1) { + return; + } + + /* + * The Linux scheduling domain can't be parsed when the multiple CPUs + * in one cluster have been associated with different NUMA nodes. However, + * it's fine to associate one NUMA node with CPUs in different clusters. + */ + for (i = 0; i < possible_cpus->len; i++) { + for (j = i + 1; j < possible_cpus->len; j++) { + if (cpus[i].props.has_socket_id && + cpus[i].props.has_cluster_id && + cpus[i].props.has_node_id && + cpus[j].props.has_socket_id && + cpus[j].props.has_cluster_id && + cpus[j].props.has_node_id && + cpus[i].props.socket_id == cpus[j].props.socket_id && + cpus[i].props.cluster_id == cpus[j].props.cluster_id && + cpus[i].props.node_id != cpus[j].props.node_id) { + warn_report("CPU-%d and CPU-%d in socket-%" PRId64 "-cluster-%" PRId64 + " have been associated with node-%" PRId64 " and node-%" PRId64 + " respectively. It can cause OSes like Linux to" + " misbehave", i, j, cpus[i].props.socket_id, + cpus[i].props.cluster_id, cpus[i].props.node_id, + cpus[j].props.node_id); + } + } + } +} + MemoryRegion *machine_consume_memdev(MachineState *machine, HostMemoryBackend *backend) { @@ -1355,6 +1394,9 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error * numa_complete_configuration(machine); if (machine->numa_state->num_nodes) { machine_numa_finish_cpu_init(machine); + if (machine_class->cpu_cluster_has_numa_boundary) { + validate_cpu_cluster_to_numa_boundary(machine); + } } } diff --git a/include/hw/boards.h b/include/hw/boards.h index a385010909..6b267c21ce 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -274,6 +274,7 @@ struct MachineClass { bool nvdimm_supported; bool numa_mem_supported; bool auto_enable_numa; + bool cpu_cluster_has_numa_boundary; SMPCompatProps smp_props; const char *default_ram_id; From fecff672351ace5e39adf7dbcf7a8ee748b201cb Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 9 May 2023 10:27:38 +1000 Subject: [PATCH 04/18] hw/arm: Validate cluster and NUMA node boundary There are two ARM machines where NUMA is aware: 'virt' and 'sbsa-ref'. Both of them are required to follow cluster-NUMA-node boundary. To enable the validation to warn about the irregular configuration where multiple CPUs in one cluster have been associated with different NUMA nodes. Signed-off-by: Gavin Shan Acked-by: Igor Mammedov Message-Id: <20230509002739.18388-3-gshan@redhat.com> Signed-off-by: Paolo Bonzini --- hw/arm/sbsa-ref.c | 2 ++ hw/arm/virt.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 0639f97dd5..b774d80291 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -910,6 +910,8 @@ static void sbsa_ref_class_init(ObjectClass *oc, void *data) mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids; mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props; mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; } static const TypeInfo sbsa_ref_info = { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9b9f7d9c68..3937e30477 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3033,6 +3033,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->smp_props.clusters_supported = true; mc->auto_enable_numa_with_memhp = true; mc->auto_enable_numa_with_memdev = true; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; mc->default_ram_id = "mach-virt.ram"; mc->default_nic = "virtio-net-pci"; From 3d9981cde964ea80f9c58072ddbb4df8b5a7183a Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 9 May 2023 10:27:39 +1000 Subject: [PATCH 05/18] hw/riscv: Validate cluster and NUMA node boundary There are two RISCV machines where NUMA is aware: 'virt' and 'spike'. Both of them are required to follow cluster-NUMA-node boundary. To enable the validation to warn about the irregular configuration where multiple CPUs in one cluster has been associated with multiple NUMA nodes. Signed-off-by: Gavin Shan Reviewed-by: Daniel Henrique Barboza Acked-by: Igor Mammedov Acked-by: Alistair Francis Message-Id: <20230509002739.18388-4-gshan@redhat.com> Signed-off-by: Paolo Bonzini --- hw/riscv/spike.c | 2 ++ hw/riscv/virt.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 2c5546560a..81f7e53aed 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -354,6 +354,8 @@ static void spike_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; mc->numa_mem_supported = true; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; mc->default_ram_id = "riscv.spike.ram"; object_class_property_add_str(oc, "signature", NULL, spike_set_signature); object_class_property_set_description(oc, "signature", diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 95708d890e..ed4c27487e 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1669,6 +1669,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; mc->numa_mem_supported = true; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; mc->default_ram_id = "riscv_virt_board.ram"; assert(!mc->get_hotplug_handler); mc->get_hotplug_handler = virt_machine_get_hotplug_handler; From 3b6f485275ae95a81eec589d2773b86ca9ddec4d Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Sun, 18 Jun 2023 23:24:40 +0200 Subject: [PATCH 06/18] kvm: reuse per-vcpu stats fd to avoid vcpu interruption A regression has been detected in latency testing of KVM guests. More specifically, it was observed that the cyclictest numbers inside of an isolated vcpu (running on isolated pcpu) are: Where a maximum of 50us is acceptable. The implementation of KVM_GET_STATS_FD uses run_on_cpu to query per vcpu statistics, which interrupts the vcpu (and is unnecessary). To fix this, open the per vcpu stats fd on vcpu initialization, and read from that fd from QEMU's main thread. Signed-off-by: Marcelo Tosatti Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 30 +++++++++++++++--------------- include/hw/core/cpu.h | 1 + 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 7679f397ae..9aa898db14 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -450,6 +450,8 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) "kvm_init_vcpu: kvm_arch_init_vcpu failed (%lu)", kvm_arch_vcpu_id(cpu)); } + cpu->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + err: return ret; } @@ -4007,7 +4009,7 @@ static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd /* Read stats header */ kvm_stats_header = &descriptors->kvm_stats_header; - ret = read(stats_fd, kvm_stats_header, sizeof(*kvm_stats_header)); + ret = pread(stats_fd, kvm_stats_header, sizeof(*kvm_stats_header), 0); if (ret != sizeof(*kvm_stats_header)) { error_setg(errp, "KVM stats: failed to read stats header: " "expected %zu actual %zu", @@ -4038,7 +4040,8 @@ static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd } static void query_stats(StatsResultList **result, StatsTarget target, - strList *names, int stats_fd, Error **errp) + strList *names, int stats_fd, CPUState *cpu, + Error **errp) { struct kvm_stats_desc *kvm_stats_desc; struct kvm_stats_header *kvm_stats_header; @@ -4096,7 +4099,7 @@ static void query_stats(StatsResultList **result, StatsTarget target, break; case STATS_TARGET_VCPU: add_stats_entry(result, STATS_PROVIDER_KVM, - current_cpu->parent_obj.canonical_path, + cpu->parent_obj.canonical_path, stats_list); break; default: @@ -4133,10 +4136,9 @@ static void query_stats_schema(StatsSchemaList **result, StatsTarget target, add_stats_schema(result, STATS_PROVIDER_KVM, target, stats_list); } -static void query_stats_vcpu(CPUState *cpu, run_on_cpu_data data) +static void query_stats_vcpu(CPUState *cpu, StatsArgs *kvm_stats_args) { - StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr; - int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + int stats_fd = cpu->kvm_vcpu_stats_fd; Error *local_err = NULL; if (stats_fd == -1) { @@ -4145,14 +4147,13 @@ static void query_stats_vcpu(CPUState *cpu, run_on_cpu_data data) return; } query_stats(kvm_stats_args->result.stats, STATS_TARGET_VCPU, - kvm_stats_args->names, stats_fd, kvm_stats_args->errp); - close(stats_fd); + kvm_stats_args->names, stats_fd, cpu, + kvm_stats_args->errp); } -static void query_stats_schema_vcpu(CPUState *cpu, run_on_cpu_data data) +static void query_stats_schema_vcpu(CPUState *cpu, StatsArgs *kvm_stats_args) { - StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr; - int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + int stats_fd = cpu->kvm_vcpu_stats_fd; Error *local_err = NULL; if (stats_fd == -1) { @@ -4162,7 +4163,6 @@ static void query_stats_schema_vcpu(CPUState *cpu, run_on_cpu_data data) } query_stats_schema(kvm_stats_args->result.schema, STATS_TARGET_VCPU, stats_fd, kvm_stats_args->errp); - close(stats_fd); } static void query_stats_cb(StatsResultList **result, StatsTarget target, @@ -4180,7 +4180,7 @@ static void query_stats_cb(StatsResultList **result, StatsTarget target, error_setg_errno(errp, errno, "KVM stats: ioctl failed"); return; } - query_stats(result, target, names, stats_fd, errp); + query_stats(result, target, names, stats_fd, NULL, errp); close(stats_fd); break; } @@ -4194,7 +4194,7 @@ static void query_stats_cb(StatsResultList **result, StatsTarget target, if (!apply_str_list_filter(cpu->parent_obj.canonical_path, targets)) { continue; } - run_on_cpu(cpu, query_stats_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args)); + query_stats_vcpu(cpu, &stats_args); } break; } @@ -4220,6 +4220,6 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp) if (first_cpu) { stats_args.result.schema = result; stats_args.errp = errp; - run_on_cpu(first_cpu, query_stats_schema_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args)); + query_stats_schema_vcpu(first_cpu, &stats_args); } } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 4871ad85f0..3b765beb9b 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -402,6 +402,7 @@ struct CPUState { struct kvm_dirty_gfn *kvm_dirty_gfns; uint32_t kvm_fetch_index; uint64_t dirty_pages; + int kvm_vcpu_stats_fd; /* Use by accel-block: CPU is executing an ioctl() */ QemuLockCnt in_ioctl_lock; From 4d714d1a0bf1fca9576ee53a1a5dfa3fd5ddae99 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Jun 2023 23:57:30 +0200 Subject: [PATCH 07/18] target/i386: fix INVD vmexit Due to a typo or perhaps a brain fart, the INVD vmexit was never generated. Fix it (but not that fixing just the typo would break both INVD and WBINVD, due to a case of two wrongs making a right). Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 08c4cab73f..0de068d4b7 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -6119,7 +6119,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0x108: /* invd */ case 0x109: /* wbinvd */ if (check_cpl0(s)) { - gen_svm_check_intercept(s, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); + gen_svm_check_intercept(s, (b & 1) ? SVM_EXIT_WBINVD : SVM_EXIT_INVD); /* nothing to do */ } break; From 8afce497e42bb279bcbc1637ecd30b70fc001947 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 00:01:58 +0200 Subject: [PATCH 08/18] target/i386: TCG supports 3DNow! prefetch(w) The AMD prefetch(w) instructions have not been deprecated together with the rest of 3DNow!, and in fact are even supported by newer Intel processor. Mark them as supported by TCG, as it supports all of 3DNow!. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1242bd541a..ff3dcd02dc 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -647,7 +647,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB | \ TCG_EXT2_X86_64_FEATURES) #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ - CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) + CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \ + CPUID_EXT3_3DNOWPREFETCH) #define TCG_EXT4_FEATURES 0 #define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | \ CPUID_SVM_SVME_ADDR_CHK) From 691925e5a3215caa6096f56070734b95054f800b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 00:05:38 +0200 Subject: [PATCH 09/18] target/i386: TCG supports RDSEED TCG implements RDSEED, and in fact uses qcrypto_random_bytes which is secure enough to match hardware behavior. Expose it to guests. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ff3dcd02dc..fc4246223d 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -657,11 +657,10 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \ - CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2) + CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_RDSEED) /* missing: CPUID_7_0_EBX_HLE - CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, - CPUID_7_0_EBX_RDSEED */ + CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */ #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES) From f9e0dbae7844738f2b7d8bdead7be506a8c7646d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Jun 2023 00:43:22 +0200 Subject: [PATCH 10/18] target/i386: do not accept RDSEED if CPUID bit absent Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 0de068d4b7..4ef45bbd71 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3925,12 +3925,20 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; case 7: /* RDSEED */ + if (mod != 3 || + (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || + !(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) { + goto illegal_op; + } + goto do_rdrand; + case 6: /* RDRAND */ if (mod != 3 || (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || !(s->cpuid_ext_features & CPUID_EXT_RDRAND)) { goto illegal_op; } + do_rdrand: translator_io_start(&s->base); gen_helper_rdrand(s->T0, cpu_env); rm = (modrm & 7) | REX_B(s); From 1420dd6a19cfbdf444af5622797d5d95a24d9461 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 01:59:35 +0200 Subject: [PATCH 11/18] target/i386: TCG supports XSAVEERPTR XSAVEERPTR is actually a fix for an errata; TCG does not have the issue. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fc4246223d..bce0cb73e8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -678,6 +678,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_SGX_12_0_EBX_FEATURES 0 #define TCG_SGX_12_1_EAX_FEATURES 0 +#define TCG_8000_0008_EBX CPUID_8000_0008_EBX_XSAVEERPTR + FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_EDX] = { .type = CPUID_FEATURE_WORD, @@ -939,7 +941,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "amd-psfd", NULL, NULL, NULL, }, .cpuid = { .eax = 0x80000008, .reg = R_EBX, }, - .tcg_features = 0, + .tcg_features = TCG_8000_0008_EBX, .unmigratable_flags = 0, }, [FEAT_8000_0021_EAX] = { From 431c51e9d48faecbd2dd3ffc49b1636f280bfe8d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Jun 2023 23:58:25 +0200 Subject: [PATCH 12/18] target/i386: TCG supports WBNOINVD WBNOINVD is the same as INVD or WBINVD as far as TCG is concerned, since there is no cache in TCG and therefore no invalidation side effect in WBNOINVD. With respect to SVM emulation, processors that do not support WBNOINVD will ignore the prefix and treat it as WBINVD, while those that support it will generate exactly the same vmexit. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 ++- target/i386/tcg/translate.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index bce0cb73e8..695e01582b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -678,7 +678,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_SGX_12_0_EBX_FEATURES 0 #define TCG_SGX_12_1_EAX_FEATURES 0 -#define TCG_8000_0008_EBX CPUID_8000_0008_EBX_XSAVEERPTR +#define TCG_8000_0008_EBX (CPUID_8000_0008_EBX_XSAVEERPTR | \ + CPUID_8000_0008_EBX_WBNOINVD) FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_EDX] = { diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 4ef45bbd71..b2e2dccb84 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -6125,7 +6125,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; case 0x108: /* invd */ - case 0x109: /* wbinvd */ + case 0x109: /* wbinvd; wbnoinvd with REPZ prefix */ if (check_cpl0(s)) { gen_svm_check_intercept(s, (b & 1) ? SVM_EXIT_WBINVD : SVM_EXIT_INVD); /* nothing to do */ From fd5dcb1ccd660e47fb9f74043a16539631f53386 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Jun 2023 15:41:42 +0200 Subject: [PATCH 13/18] target/i386: Intel only supports SYSCALL/SYSRET in long mode Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 ++++ target/i386/tcg/translate.c | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 695e01582b..978d24b5ec 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6238,6 +6238,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ecx |= 1 << 1; /* CmpLegacy bit */ } } + if (tcg_enabled() && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && + !(env->hflags & HF_LMA_MASK)) { + *edx &= ~CPUID_EXT2_SYSCALL; + } break; case 0x80000002: case 0x80000003: diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index b2e2dccb84..ed4016f554 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5692,7 +5692,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; #ifdef TARGET_X86_64 case 0x105: /* syscall */ - /* XXX: is it usable in real mode ? */ + /* For Intel SYSCALL is only valid in long mode */ + if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { + goto illegal_op; + } gen_update_cc_op(s); gen_update_eip_cur(s); gen_helper_syscall(cpu_env, cur_insn_len_i32(s)); @@ -5702,6 +5705,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_eob_worker(s, false, true); break; case 0x107: /* sysret */ + /* For Intel SYSRET is only valid in long mode */ + if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { + goto illegal_op; + } if (!PE(s)) { gen_exception_gpf(s); } else { From 75a02adf81911c14ec51b11a8ecd6c8aabcbd049 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Jun 2023 15:41:42 +0200 Subject: [PATCH 14/18] target/i386: AMD only supports SYSENTER/SYSEXIT in 32-bit mode Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index ed4016f554..a20b5af71e 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5669,9 +5669,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) s->base.is_jmp = DISAS_NORETURN; break; case 0x134: /* sysenter */ - /* For Intel SYSENTER is valid on 64-bit */ - if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) + /* For AMD SYSENTER is not valid in long mode */ + if (LMA(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { goto illegal_op; + } if (!PE(s)) { gen_exception_gpf(s); } else { @@ -5680,9 +5681,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } break; case 0x135: /* sysexit */ - /* For Intel SYSEXIT is valid on 64-bit */ - if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) + /* For AMD SYSEXIT is not valid in long mode */ + if (LMA(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { goto illegal_op; + } if (!PE(s)) { gen_exception_gpf(s); } else { From 53b9b4cc9fb956279c6494bfa7d7ea61f07bb214 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Jun 2023 15:29:12 +0200 Subject: [PATCH 15/18] target/i386: sysret and sysexit are privileged Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a20b5af71e..66800392bb 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5685,7 +5685,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (LMA(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { goto illegal_op; } - if (!PE(s)) { + if (!PE(s) || CPL(s) != 0) { gen_exception_gpf(s); } else { gen_helper_sysexit(cpu_env, tcg_constant_i32(dflag - 1)); @@ -5711,7 +5711,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { goto illegal_op; } - if (!PE(s)) { + if (!PE(s) || CPL(s) != 0) { gen_exception_gpf(s); } else { gen_helper_sysret(cpu_env, tcg_constant_i32(dflag - 1)); From 6750485bf42a9917a29487aec899687669104e07 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Jun 2023 00:47:31 +0200 Subject: [PATCH 16/18] target/i386: implement RDPID in TCG RDPID corresponds to a RDMSR(TSC_AUX); however, it is unprivileged so for user-mode emulation we must provide the value that the kernel places in the MSR. For Linux, it is a combination of the current CPU and the current NUMA node, both of which can be retrieved with getcpu(2). Also try sched_getcpu(), which might be there on the BSDs. If there is no portable way to retrieve the current CPU id from userspace, return 0. RDTSCP is reimplemented as RDTSC + RDPID ECX; the differences in terms of serializability are not relevant to QEMU. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- meson.build | 2 ++ target/i386/cpu.c | 10 +++++++++- target/i386/helper.h | 2 +- target/i386/tcg/misc_helper.c | 21 +++++++++++++++------ target/i386/tcg/translate.c | 24 +++++++++++++++++++----- 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/meson.build b/meson.build index 6ef78ea278..3e3d38badb 100644 --- a/meson.build +++ b/meson.build @@ -2232,6 +2232,8 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime')) config_host_data.set('CONFIG_DUP3', cc.has_function('dup3')) config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate')) config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate')) +config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix)) +config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include ')) # Note that we need to specify prefix: here to avoid incorrectly # thinking that Windows has posix_memalign() config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign', prefix: '#include ')) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 978d24b5ec..4d52e612ac 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -661,9 +661,17 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, /* missing: CPUID_7_0_EBX_HLE CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */ + +#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX +#define TCG_7_0_ECX_RDPID CPUID_7_0_ECX_RDPID +#else +#define TCG_7_0_ECX_RDPID 0 +#endif #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES) + CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES | \ + TCG_7_0_ECX_RDPID) + #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ CPUID_7_1_EAX_FSRC) diff --git a/target/i386/helper.h b/target/i386/helper.h index 48609c210b..c93c1d6c8f 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -69,8 +69,8 @@ DEF_HELPER_2(into, void, env, int) DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env) DEF_HELPER_1(rechecking_single_step, void, env) DEF_HELPER_1(cpuid, void, env) +DEF_HELPER_FLAGS_1(rdpid, TCG_CALL_NO_WG, tl, env) DEF_HELPER_1(rdtsc, void, env) -DEF_HELPER_1(rdtscp, void, env) DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env) #ifndef CONFIG_USER_ONLY diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index 5f7a3061ca..868f36ab7f 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -75,12 +75,6 @@ void helper_rdtsc(CPUX86State *env) env->regs[R_EDX] = (uint32_t)(val >> 32); } -void helper_rdtscp(CPUX86State *env) -{ - helper_rdtsc(env); - env->regs[R_ECX] = (uint32_t)(env->tsc_aux); -} - G_NORETURN void helper_rdpmc(CPUX86State *env) { if (((env->cr[4] & CR4_PCE_MASK) == 0 ) && @@ -137,3 +131,18 @@ void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val) env->pkru = val; tlb_flush(cs); } + +target_ulong HELPER(rdpid)(CPUX86State *env) +{ +#if defined CONFIG_SOFTMMU + return env->tsc_aux; +#elif defined CONFIG_LINUX && defined CONFIG_GETCPU + unsigned cpu, node; + getcpu(&cpu, &node); + return (node << 12) | (cpu & 0xfff); +#elif defined CONFIG_SCHED_GETCPU + return sched_getcpu(); +#else + return 0; +#endif +} diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 66800392bb..a6c2424133 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3924,13 +3924,25 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_cmpxchg8b(s, env, modrm); break; - case 7: /* RDSEED */ + case 7: /* RDSEED, RDPID with f3 prefix */ if (mod != 3 || - (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || - !(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) { + (s->prefix & (PREFIX_LOCK | PREFIX_REPNZ))) { goto illegal_op; } - goto do_rdrand; + if (s->prefix & PREFIX_REPZ) { + if (!(s->cpuid_ext_features & CPUID_7_0_ECX_RDPID)) { + goto illegal_op; + } + gen_helper_rdpid(s->T0, cpu_env); + rm = (modrm & 7) | REX_B(s); + gen_op_mov_reg_v(s, dflag, rm, s->T0); + break; + } else { + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) { + goto illegal_op; + } + goto do_rdrand; + } case 6: /* RDRAND */ if (mod != 3 || @@ -6125,7 +6137,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_update_cc_op(s); gen_update_eip_cur(s); translator_io_start(&s->base); - gen_helper_rdtscp(cpu_env); + gen_helper_rdtsc(cpu_env); + gen_helper_rdpid(s->T0, cpu_env); + gen_op_mov_reg_v(s, dflag, R_ECX, s->T0); break; default: From 63fd8ef080351357c0cb0644ed63fd3e2a8833a8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 01:01:29 +0200 Subject: [PATCH 17/18] target/i386: implement SYSCALL/SYSRET in 32-bit emulators AMD supports both 32-bit and 64-bit SYSCALL/SYSRET, but the TCG only exposes it for 64-bit targets. For system emulation just reuse the helper; for user-mode emulation the ABI is the same as "int $80". The BSDs does not support any fast system call mechanism in 32-bit mode so add to bsd-user the same stub that FreeBSD has for 64-bit compatibility mode. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- bsd-user/i386/target_arch_cpu.h | 4 ++++ linux-user/i386/cpu_loop.c | 9 +++++---- target/i386/cpu.c | 4 ++-- target/i386/helper.h | 2 -- target/i386/tcg/seg_helper.c | 7 +++++-- target/i386/tcg/sysemu/seg_helper.c | 7 ++++--- target/i386/tcg/translate.c | 2 -- target/i386/tcg/user/seg_helper.c | 2 -- 8 files changed, 20 insertions(+), 17 deletions(-) diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h index d792dc720f..9bf2c4244b 100644 --- a/bsd-user/i386/target_arch_cpu.h +++ b/bsd-user/i386/target_arch_cpu.h @@ -164,6 +164,10 @@ static inline void target_cpu_loop(CPUX86State *env) } break; + case EXCP_SYSCALL: + /* doesn't do anything */ + break; + case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 2d0918a93f..9eeda551ea 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -211,6 +211,9 @@ void cpu_loop(CPUX86State *env) switch(trapnr) { case 0x80: +#ifndef TARGET_X86_64 + case EXCP_SYSCALL: +#endif /* linux syscall from int $0x80 */ ret = do_syscall(env, env->regs[R_EAX], @@ -227,9 +230,9 @@ void cpu_loop(CPUX86State *env) env->regs[R_EAX] = ret; } break; -#ifndef TARGET_ABI32 +#ifdef TARGET_X86_64 case EXCP_SYSCALL: - /* linux syscall from syscall instruction */ + /* linux syscall from syscall instruction. */ ret = do_syscall(env, env->regs[R_EAX], env->regs[R_EDI], @@ -245,8 +248,6 @@ void cpu_loop(CPUX86State *env) env->regs[R_EAX] = ret; } break; -#endif -#ifdef TARGET_X86_64 case EXCP_VSYSCALL: emulate_vsyscall(env); break; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 4d52e612ac..c0fb6b3ad9 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -637,7 +637,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER */ #ifdef TARGET_X86_64 -#define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM) +#define TCG_EXT2_X86_64_FEATURES CPUID_EXT2_LM #else #define TCG_EXT2_X86_64_FEATURES 0 #endif @@ -645,7 +645,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \ CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \ CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB | \ - TCG_EXT2_X86_64_FEATURES) + CPUID_EXT2_SYSCALL | TCG_EXT2_X86_64_FEATURES) #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \ CPUID_EXT3_3DNOWPREFETCH) diff --git a/target/i386/helper.h b/target/i386/helper.h index c93c1d6c8f..ac2b04abd6 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -51,10 +51,8 @@ DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int) DEF_HELPER_1(sysenter, void, env) DEF_HELPER_2(sysexit, void, env, int) -#ifdef TARGET_X86_64 DEF_HELPER_2(syscall, void, env, int) DEF_HELPER_2(sysret, void, env, int) -#endif DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int) DEF_HELPER_FLAGS_3(raise_interrupt, TCG_CALL_NO_WG, noreturn, env, int, int) DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, int) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 03b58e94a2..e8d19c65fd 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -977,6 +977,7 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, e2); env->eip = offset; } +#endif /* TARGET_X86_64 */ void helper_sysret(CPUX86State *env, int dflag) { @@ -990,6 +991,7 @@ void helper_sysret(CPUX86State *env, int dflag) raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); } selector = (env->star >> 48) & 0xffff; +#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | @@ -1015,7 +1017,9 @@ void helper_sysret(CPUX86State *env, int dflag) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); - } else { + } else +#endif + { env->eflags |= IF_MASK; cpu_x86_load_seg_cache(env, R_CS, selector | 3, 0, 0xffffffff, @@ -1030,7 +1034,6 @@ void helper_sysret(CPUX86State *env, int dflag) DESC_W_MASK | DESC_A_MASK); } } -#endif /* TARGET_X86_64 */ /* real mode interrupt */ static void do_interrupt_real(CPUX86State *env, int intno, int is_int, diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c index 2c9bd007ad..1cb5a0db45 100644 --- a/target/i386/tcg/sysemu/seg_helper.c +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -26,7 +26,6 @@ #include "tcg/helper-tcg.h" #include "../seg_helper.h" -#ifdef TARGET_X86_64 void helper_syscall(CPUX86State *env, int next_eip_addend) { int selector; @@ -35,6 +34,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); } selector = (env->star >> 32) & 0xffff; +#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { int code64; @@ -61,7 +61,9 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) } else { env->eip = env->cstar; } - } else { + } else +#endif + { env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend); env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); @@ -78,7 +80,6 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) env->eip = (uint32_t)env->star; } } -#endif /* TARGET_X86_64 */ void handle_even_inj(CPUX86State *env, int intno, int is_int, int error_code, int is_hw, int rm) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a6c2424133..28cb3fb7f4 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5704,7 +5704,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) s->base.is_jmp = DISAS_EOB_ONLY; } break; -#ifdef TARGET_X86_64 case 0x105: /* syscall */ /* For Intel SYSCALL is only valid in long mode */ if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { @@ -5738,7 +5737,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_eob_worker(s, false, true); } break; -#endif case 0x1a2: /* cpuid */ gen_update_cc_op(s); gen_update_eip_cur(s); diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c index 67481b0aa8..c45f2ac2ba 100644 --- a/target/i386/tcg/user/seg_helper.c +++ b/target/i386/tcg/user/seg_helper.c @@ -26,7 +26,6 @@ #include "tcg/helper-tcg.h" #include "tcg/seg_helper.h" -#ifdef TARGET_X86_64 void helper_syscall(CPUX86State *env, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -36,7 +35,6 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) env->exception_next_eip = env->eip + next_eip_addend; cpu_loop_exit(cs); } -#endif /* TARGET_X86_64 */ /* * fake user mode interrupt. is_int is TRUE if coming from the int From 8edddaa23d75c57e093d99bf098a39f8cbd227c7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 18 Jun 2023 23:10:39 +0200 Subject: [PATCH 18/18] git-submodule.sh: allow running in validate mode without previous update The call to git-submodule.sh done in configure may happen without a previous checkout of the roms/SLOF submodule, or even without a previous run of the script. So, handle creating a .git-submodule-status file even in validate mode. If git is absent, ensure that all passed directories exists (because you should be in a fresh untar and will not have stale arguments to git-submodule.sh) but do no other checks. If git is present, ensure that .git-submodule-status contains an entry for all submodules passed on the command line. With this change, "ignore" mode is not needed anymore. Reported-by: Nina Schoetterl-Glausch Fixes: b11f9bd96f4 ("configure: move SLOF submodule handling to pc-bios/s390-ccw", 2023-06-06) Signed-off-by: Paolo Bonzini --- configure | 2 +- scripts/git-submodule.sh | 73 ++++++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/configure b/configure index 86363a7e50..2b41c49c0d 100755 --- a/configure +++ b/configure @@ -758,7 +758,7 @@ done if ! test -e "$source_path/.git" then - git_submodules_action="ignore" + git_submodules_action="validate" fi # test for any invalid configuration combinations diff --git a/scripts/git-submodule.sh b/scripts/git-submodule.sh index 11fad2137c..335f7f5fdf 100755 --- a/scripts/git-submodule.sh +++ b/scripts/git-submodule.sh @@ -9,13 +9,22 @@ command=$1 shift maybe_modules="$@" -# if not running in a git checkout, do nothing -test "$command" = "ignore" && exit 0 - +test -z "$maybe_modules" && exit 0 test -z "$GIT" && GIT=$(command -v git) cd "$(dirname "$0")/.." +no_git_error= +if ! test -e ".git"; then + no_git_error='no git checkout exists' +elif test -z "$GIT"; then + no_git_error='git binary not found' +fi + +is_git() { + test -z "$no_git_error" +} + update_error() { echo "$0: $*" echo @@ -34,7 +43,7 @@ update_error() { } validate_error() { - if test "$1" = "validate"; then + if is_git && test "$1" = "validate"; then echo "GIT submodules checkout is out of date, and submodules" echo "configured for validate only. Please run" echo " scripts/git-submodule.sh update $maybe_modules" @@ -51,42 +60,42 @@ check_updated() { test "$CURSTATUS" = "$OLDSTATUS" } -if test -n "$maybe_modules" && ! test -e ".git" -then - echo "$0: unexpectedly called with submodules but no git checkout exists" - exit 1 +if is_git; then + test -e $substat || touch $substat + modules="" + for m in $maybe_modules + do + $GIT submodule status $m 1> /dev/null 2>&1 + if test $? = 0 + then + modules="$modules $m" + grep $m $substat > /dev/null 2>&1 || $GIT submodule status $module >> $substat + else + echo "warn: ignoring non-existent submodule $m" + fi + done +else + modules=$maybe_modules fi -if test -n "$maybe_modules" && test -z "$GIT" -then - echo "$0: unexpectedly called with submodules but git binary not found" - exit 1 -fi - -modules="" -for m in $maybe_modules -do - $GIT submodule status $m 1> /dev/null 2>&1 - if test $? = 0 - then - modules="$modules $m" - else - echo "warn: ignoring non-existent submodule $m" - fi -done - case "$command" in status|validate) - test -f "$substat" || validate_error "$command" - test -z "$maybe_modules" && exit 0 for module in $modules; do - check_updated $module || validate_error "$command" + if is_git; then + check_updated $module || validate_error "$command" + elif ! (set xyz "$module"/* && test -e "$2"); then + # The directory does not exist or it contains no files + echo "$0: sources not available for $module and $no_git_error" + validate_error "$command" + fi done - exit 0 ;; + update) - test -e $substat || touch $substat - test -z "$maybe_modules" && exit 0 + is_git || { + echo "$0: unexpectedly called with submodules but $no_git_error" + exit 1 + } $GIT submodule update --init $modules 1>/dev/null test $? -ne 0 && update_error "failed to update modules"