From 8a5701e54a1f6a355072751e40c0ef440a4402b3 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Wed, 9 Sep 2020 16:37:46 +0200 Subject: [PATCH 01/86] tests: add missing genh dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix high-parallelism builds by forcing all generated headers to be created before tests are compiled. Reported-by: Claudio Fontana Signed-off-by: Paolo Bonzini Tested-by: Claudio Fontana Reviewed-by: Philippe Mathieu-Daudé --- tests/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/meson.build b/tests/meson.build index 04072a64ca..8b99e23545 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -56,7 +56,7 @@ test_qapi_files = custom_target('Test QAPI files', # perhaps change qapi_gen to replace / with _, like Meson itself does? subdir('include') -libtestqapi = static_library('testqapi', sources: [test_qapi_files, test_qapi_outputs_extra]) +libtestqapi = static_library('testqapi', sources: [test_qapi_files, genh, test_qapi_outputs_extra]) testqapi = declare_dependency(link_with: libtestqapi) testblock = declare_dependency(dependencies: [block], sources: 'iothread.c') @@ -232,7 +232,7 @@ foreach test_name, extra: tests src += test_ss.all_sources() deps += test_ss.all_dependencies() endif - exe = executable(test_name, src, dependencies: deps) + exe = executable(test_name, src, genh, dependencies: deps) test(test_name, exe, depends: test_deps.get(test_name, []), From 27d551c00d5458d1deda33508dab7453959ca2c6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Sep 2020 13:12:11 +0200 Subject: [PATCH 02/86] meson: clean up build_by_default Build all executables by default except for the known-broken ones. This also allows running qemu-iotests without manually building socket_scm_helper. Reported-by: Max Reitz Tested-by: Max Reitz Signed-off-by: Paolo Bonzini --- docs/devel/build-system.rst | 5 +++++ tests/fp/meson.build | 2 -- tests/meson.build | 5 ++--- tests/qemu-iotests/meson.build | 3 +-- trace/meson.build | 1 - ui/shader/meson.build | 1 - 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index 08e85c69e1..2ee368fad6 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -193,6 +193,11 @@ compilation as possible. The Meson "sourceset" functionality is used to list the files and their dependency on various configuration symbols. +All executables are built by default, except for some `contrib/` +binaries that are known to fail to build on some platforms (for example +32-bit or big-endian platforms). Tests are also built by default, +though that might change in the future. + Various subsystems that are common to both tools and emulators have their own sourceset, for example `block_ss` for the block device subsystem, `chardev_ss` for the character device subsystem, etc. These sourcesets diff --git a/tests/fp/meson.build b/tests/fp/meson.build index 8779a17aab..24739ad421 100644 --- a/tests/fp/meson.build +++ b/tests/fp/meson.build @@ -541,7 +541,6 @@ fpcflags += [ fptest = executable( 'fp-test', ['fp-test.c', tfdir / 'slowfloat.c', '../../fpu/softfloat.c'], - build_by_default: false, link_with: [libtestfloat, libsoftfloat], dependencies: [qemuutil], include_directories: [sfinc, include_directories(tfdir)], @@ -628,7 +627,6 @@ test('fp-test:mulAdd', fptest, fpbench = executable( 'fp-bench', ['fp-bench.c', '../../fpu/softfloat.c'], - build_by_default: false, link_with: [libtestfloat, libsoftfloat], dependencies: [qemuutil], include_directories: [sfinc, include_directories(tfdir)], diff --git a/tests/meson.build b/tests/meson.build index 8b99e23545..3c2969092d 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -251,12 +251,11 @@ foreach bench_name, deps: benchs suite: ['speed']) endforeach -if have_tools and 'CONFIG_VHOST_USER' in config_host +if have_tools and 'CONFIG_VHOST_USER' in config_host and 'CONFIG_LINUX' in config_host executable('vhost-user-bridge', sources: files('vhost-user-bridge.c'), link_with: [libvhost_user], - dependencies: [qemuutil], - build_by_default: false) + dependencies: [qemuutil]) endif if have_system and 'CONFIG_POSIX' in config_host diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build index 60470936b4..67aed1e492 100644 --- a/tests/qemu-iotests/meson.build +++ b/tests/qemu-iotests/meson.build @@ -1,6 +1,5 @@ if 'CONFIG_LINUX' in config_host - socket_scm_helper = executable('socket_scm_helper', 'socket_scm_helper.c', - build_by_default: false) + socket_scm_helper = executable('socket_scm_helper', 'socket_scm_helper.c') else socket_scm_helper = [] endif diff --git a/trace/meson.build b/trace/meson.build index b36937d3a6..d5fc45c628 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -70,7 +70,6 @@ foreach d : [ output: d[0], input: meson.source_root() / 'trace-events', command: [ tracetool, '--group=root', '--format=@0@'.format(d[1]), '@INPUT@' ], - build_by_default: true, # to be removed when added to a target capture: true) specific_ss.add(gen) endforeach diff --git a/ui/shader/meson.build b/ui/shader/meson.build index f69e44ed89..592bf596b9 100644 --- a/ui/shader/meson.build +++ b/ui/shader/meson.build @@ -9,7 +9,6 @@ foreach e : shaders genh += custom_target(output, output: output, capture: true, - build_by_default: true, # to be removed when added to a target input: files('@0@.@1@'.format(e[0], e[1])), command: [shaderinclude, '@INPUT0@']) endforeach From 1d14a8edce750c9d87ba6b03276815723de9a193 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Sep 2020 13:14:38 +0200 Subject: [PATCH 03/86] ninjatool: rebuild multi-output targets if outputs are missing The "stamp file trick" used to group targets of a single multi-output rule prevents the user from deleting one such target in order to force its rebuild. Doing so will not touch the stamp file, and therefore only the dummy ":" command will be executed. With this patch, ninjatool writes rules that force-rebuild the stamp file if any of its outputs are missing. Rebuilding the missing target therefore causes the stamp file to be rebuilt too. Reported-by: Markus Armbruster Signed-off-by: Paolo Bonzini --- scripts/ninjatool.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/ninjatool.py b/scripts/ninjatool.py index 627a1cab45..6f0e35c727 100755 --- a/scripts/ninjatool.py +++ b/scripts/ninjatool.py @@ -908,6 +908,9 @@ class Ninja2Make(NinjaParserEventsWithVars): else: stamp = '%s@%s.stamp' % (rule, sha1_text(targets)[0:11]) self.print('%s: %s; @:' % (targets, stamp)) + self.print('ifneq (%s, $(wildcard %s))' % (targets, targets)) + self.print('.PHONY: %s' % (stamp, )) + self.print('endif') self.print('%s: %s | %s; ${ninja-command-restat}' % (stamp, inputs, orderonly)) self.rule_targets[rule].append(stamp) self.stamp_targets[rule].append(stamp) From 18240fdcaa890cf1873fc2cd961411ab22183968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 11 Sep 2020 14:42:47 +0200 Subject: [PATCH 04/86] meson: fix MSI rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The environment variables can't be passed through an env: argument yet (meson#2723), use 'env' as suggested in: https://github.com/mesonbuild/meson/issues/2723#issuecomment-348630957 Signed-off-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- qga/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/qga/meson.build b/qga/meson.build index 1c312b50cc..cd08bd953a 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -69,6 +69,7 @@ if targetos == 'windows' output: 'qemu-ga-@0@.msi'.format(config_host['ARCH']), depends: deps, command: [ + find_program('env'), 'QEMU_GA_VERSION=' + config_host['QEMU_GA_VERSION'], 'QEMU_GA_MANUFACTURER=' + config_host['QEMU_GA_MANUFACTURER'], 'QEMU_GA_DISTRO=' + config_host['QEMU_GA_DISTRO'], From 8fe11232c8ad0fecbfab0ea804bfdef0bbec0da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 11 Sep 2020 14:42:48 +0200 Subject: [PATCH 05/86] meson: error out if qemu_suffix starts with / MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the variable is used for path concatenation, the result would ignore the prefix directory altogether. Signed-off-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index 5b586afc38..9755be79fd 100644 --- a/meson.build +++ b/meson.build @@ -17,6 +17,11 @@ config_host = keyval.load(meson.current_build_dir() / 'config-host.mak') enable_modules = 'CONFIG_MODULES' in config_host enable_static = 'CONFIG_STATIC' in config_host build_docs = 'BUILD_DOCS' in config_host + +if get_option('qemu_suffix').startswith('/') + error('qemu_suffix cannot start with a /') +endif + qemu_datadir = get_option('datadir') / get_option('qemu_suffix') qemu_docdir = get_option('docdir') / get_option('qemu_suffix') config_host_data = configuration_data() From 5c8e1e832822f2e5bc630864a77eea40ee520a4f Mon Sep 17 00:00:00 2001 From: Sunil Muthuswamy Date: Thu, 30 Jul 2020 22:11:26 +0000 Subject: [PATCH 06/86] WHPX: vmware cpuid leaf for tsc and apic frequency Newer versions of WHPX provide the capability to query the tsc and apic frequency. Expose these through the vmware cpuid leaf. This patch doesnt support setting the tsc frequency; that will come as a separate fix. Signed-off-by: Sunil Muthuswamy Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/whp-dispatch.h | 3 +- target/i386/whpx-all.c | 96 +++++++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/target/i386/whp-dispatch.h b/target/i386/whp-dispatch.h index e4695c349f..b18aba20ed 100644 --- a/target/i386/whp-dispatch.h +++ b/target/i386/whp-dispatch.h @@ -2,10 +2,11 @@ #define WHP_DISPATCH_H #include - #include #include +#define WHV_E_UNKNOWN_CAPABILITY 0x80370300L + #define LIST_WINHVPLATFORM_FUNCTIONS(X) \ X(HRESULT, WHvGetCapability, (WHV_CAPABILITY_CODE CapabilityCode, VOID* CapabilityBuffer, UINT32 CapabilityBufferSizeInBytes, UINT32* WrittenSizeInBytes)) \ X(HRESULT, WHvCreatePartition, (WHV_PARTITION_HANDLE* Partition)) \ diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c index 5a0f337a4c..2a8fcb68fd 100644 --- a/target/i386/whpx-all.c +++ b/target/i386/whpx-all.c @@ -27,6 +27,8 @@ #include #include +#define HYPERV_APIC_BUS_FREQUENCY (200000000ULL) + struct whpx_state { uint64_t mem_quota; WHV_PARTITION_HANDLE partition; @@ -1061,6 +1063,18 @@ static int whpx_vcpu_run(CPUState *cpu) cpu_x86_cpuid(env, cpuid_fn, 0, (UINT32 *)&rax, (UINT32 *)&rbx, (UINT32 *)&rcx, (UINT32 *)&rdx); switch (cpuid_fn) { + case 0x40000000: + /* Expose the vmware cpu frequency cpuid leaf */ + rax = 0x40000010; + rbx = rcx = rdx = 0; + break; + + case 0x40000010: + rax = env->tsc_khz; + rbx = env->apic_bus_freq / 1000; /* Hz to KHz */ + rcx = rdx = 0; + break; + case 0x80000001: /* Remove any support of OSVW */ rcx &= ~CPUID_EXT3_OSVW; @@ -1191,8 +1205,12 @@ int whpx_init_vcpu(CPUState *cpu) { HRESULT hr; struct whpx_state *whpx = &whpx_global; - struct whpx_vcpu *vcpu; + struct whpx_vcpu *vcpu = NULL; Error *local_error = NULL; + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + X86CPU *x86_cpu = X86_CPU(cpu); + UINT64 freq = 0; + int ret; /* Add migration blockers for all unsupported features of the * Windows Hypervisor Platform @@ -1207,7 +1225,8 @@ int whpx_init_vcpu(CPUState *cpu) error_report_err(local_error); migrate_del_blocker(whpx_migration_blocker); error_free(whpx_migration_blocker); - return -EINVAL; + ret = -EINVAL; + goto error; } } @@ -1215,7 +1234,8 @@ int whpx_init_vcpu(CPUState *cpu) if (!vcpu) { error_report("WHPX: Failed to allocte VCPU context."); - return -ENOMEM; + ret = -ENOMEM; + goto error; } hr = whp_dispatch.WHvEmulatorCreateEmulator( @@ -1224,8 +1244,8 @@ int whpx_init_vcpu(CPUState *cpu) if (FAILED(hr)) { error_report("WHPX: Failed to setup instruction completion support," " hr=%08lx", hr); - g_free(vcpu); - return -EINVAL; + ret = -EINVAL; + goto error; } hr = whp_dispatch.WHvCreateVirtualProcessor( @@ -1234,17 +1254,72 @@ int whpx_init_vcpu(CPUState *cpu) error_report("WHPX: Failed to create a virtual processor," " hr=%08lx", hr); whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); - g_free(vcpu); - return -EINVAL; + ret = -EINVAL; + goto error; + } + + /* + * vcpu's TSC frequency is either specified by user, or use the value + * provided by Hyper-V if the former is not present. In the latter case, we + * query it from Hyper-V and record in env->tsc_khz, so that vcpu's TSC + * frequency can be migrated later via this field. + */ + if (!env->tsc_khz) { + hr = whp_dispatch.WHvGetCapability( + WHvCapabilityCodeProcessorClockFrequency, &freq, sizeof(freq), + NULL); + if (hr != WHV_E_UNKNOWN_CAPABILITY) { + if (FAILED(hr)) { + printf("WHPX: Failed to query tsc frequency, hr=0x%08lx\n", hr); + } else { + env->tsc_khz = freq / 1000; /* Hz to KHz */ + } + } + } + + env->apic_bus_freq = HYPERV_APIC_BUS_FREQUENCY; + hr = whp_dispatch.WHvGetCapability( + WHvCapabilityCodeInterruptClockFrequency, &freq, sizeof(freq), NULL); + if (hr != WHV_E_UNKNOWN_CAPABILITY) { + if (FAILED(hr)) { + printf("WHPX: Failed to query apic bus frequency hr=0x%08lx\n", hr); + } else { + env->apic_bus_freq = freq; + } + } + + /* + * If the vmware cpuid frequency leaf option is set, and we have a valid + * tsc value, trap the corresponding cpuid's. + */ + if (x86_cpu->vmware_cpuid_freq && env->tsc_khz) { + UINT32 cpuidExitList[] = {1, 0x80000001, 0x40000000, 0x40000010}; + + hr = whp_dispatch.WHvSetPartitionProperty( + whpx->partition, + WHvPartitionPropertyCodeCpuidExitList, + cpuidExitList, + RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32)); + + if (FAILED(hr)) { + error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx", + hr); + ret = -EINVAL; + goto error; + } } vcpu->interruptable = true; - cpu->vcpu_dirty = true; cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu; qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr); return 0; + +error: + g_free(vcpu); + + return ret; } int whpx_vcpu_exec(CPUState *cpu) @@ -1493,6 +1568,7 @@ static int whpx_accel_init(MachineState *ms) WHV_CAPABILITY whpx_cap; UINT32 whpx_cap_size; WHV_PARTITION_PROPERTY prop; + UINT32 cpuidExitList[] = {1, 0x80000001}; whpx = &whpx_global; @@ -1551,7 +1627,6 @@ static int whpx_accel_init(MachineState *ms) goto error; } - UINT32 cpuidExitList[] = {1, 0x80000001}; hr = whp_dispatch.WHvSetPartitionProperty( whpx->partition, WHvPartitionPropertyCodeCpuidExitList, @@ -1579,14 +1654,13 @@ static int whpx_accel_init(MachineState *ms) printf("Windows Hypervisor Platform accelerator is operational\n"); return 0; - error: +error: if (NULL != whpx->partition) { whp_dispatch.WHvDeletePartition(whpx->partition); whpx->partition = NULL; } - return ret; } From 738c7236d17cd3b424f001e9ffbf6b9a482ad00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 10 Sep 2020 07:45:16 +0200 Subject: [PATCH 07/86] configure: Do not intent to build WHPX on 32-bit host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hyper-V is available on 64-bit versions of Windows, do not try to build its support on 32-bit versions. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200910054516.405777-1-f4bug@amsat.org> Reviewed-by: Stefan Weil Signed-off-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé --- configure | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure b/configure index ecc8e90e8b..9e1989976f 100755 --- a/configure +++ b/configure @@ -2986,7 +2986,10 @@ fi ########################################## # Windows Hypervisor Platform accelerator (WHPX) check -if test "$whpx" != "no" ; then +if test "$whpx" = "yes" && test "$ARCH" != "x86_64"; then + error_exit "WHPX requires 64-bit host" +fi +if test "$whpx" != "no" && test "$ARCH" = "x86_64"; then if check_include "WinHvPlatform.h" && check_include "WinHvEmulation.h"; then whpx="yes" else From 1b7e01d00854cb053d8dbed6a064038c162a27ef Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 9 Sep 2020 10:08:51 +0100 Subject: [PATCH 08/86] MAINTAINERS: add Paolo Bonzini as RCU maintainer The RCU code that Paolo maintains is missing a MAINTAINERS file entry. Signed-off-by: Stefan Hajnoczi Message-Id: <20200909090851.14458-1-stefanha@redhat.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e1e8ae277d..2c8366d3a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2313,6 +2313,14 @@ F: softmmu/cpus.c F: softmmu/cpu-throttle.c F: qapi/run-state.json +Read, Copy, Update (RCU) +M: Paolo Bonzini +S: Maintained +F: include/qemu/rcu*.h +F: tests/rcutorture.c +F: tests/test-rcu-*.c +F: util/rcu.c + Human Monitor (HMP) M: Dr. David Alan Gilbert S: Maintained From db5daafab2dadc029f48e6a64c3cf0c6e44d35f8 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 8 Sep 2020 16:12:06 +0200 Subject: [PATCH 09/86] target/i386: support KVM_FEATURE_ASYNC_PF_INT Linux-5.8 introduced interrupt based mechanism for 'page ready' events delivery and disabled the old, #PF based one (see commit 2635b5c4a0e4 "KVM: x86: interrupt based APF 'page ready' event delivery"). Linux guest switches to using in in 5.9 (see commit b1d405751cd5 "KVM: x86: Switch KVM guest to using interrupts for page ready APF delivery"). The feature has a new KVM_FEATURE_ASYNC_PF_INT bit assigned and the interrupt vector is set in MSR_KVM_ASYNC_PF_INT MSR. Support this in QEMU. Signed-off-by: Vitaly Kuznetsov Message-Id: <20200908141206.357450-1-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 ++- target/i386/cpu.h | 1 + target/i386/kvm.c | 10 ++++++++++ target/i386/machine.c | 19 +++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3ffd877dd5..0ea0630e1f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -799,7 +799,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "kvmclock", "kvm-nopiodelay", "kvm-mmu", "kvmclock", "kvm-asyncpf", "kvm-steal-time", "kvm-pv-eoi", "kvm-pv-unhalt", NULL, "kvm-pv-tlb-flush", NULL, "kvm-pv-ipi", - "kvm-poll-control", "kvm-pv-sched-yield", NULL, NULL, + "kvm-poll-control", "kvm-pv-sched-yield", "kvm-asyncpf-int", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "kvmclock-stable-bit", NULL, NULL, NULL, @@ -6988,6 +6988,7 @@ static void x86_cpu_initfn(Object *obj) object_property_add_alias(obj, "kvm_nopiodelay", obj, "kvm-nopiodelay"); object_property_add_alias(obj, "kvm_mmu", obj, "kvm-mmu"); object_property_add_alias(obj, "kvm_asyncpf", obj, "kvm-asyncpf"); + object_property_add_alias(obj, "kvm_asyncpf_int", obj, "kvm-asyncpf-int"); object_property_add_alias(obj, "kvm_steal_time", obj, "kvm-steal-time"); object_property_add_alias(obj, "kvm_pv_eoi", obj, "kvm-pv-eoi"); object_property_add_alias(obj, "kvm_pv_unhalt", obj, "kvm-pv-unhalt"); diff --git a/target/i386/cpu.h b/target/i386/cpu.h index f519d2bfd4..51c1d5f60a 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1492,6 +1492,7 @@ typedef struct CPUX86State { uint64_t wall_clock_msr; uint64_t steal_time_msr; uint64_t async_pf_en_msr; + uint64_t async_pf_int_msr; uint64_t pv_eoi_en_msr; uint64_t poll_control_msr; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 9efb07e7c8..06c2025c67 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -287,6 +287,7 @@ static const struct kvm_para_features { { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY }, { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, + { KVM_CAP_ASYNC_PF_INT, KVM_FEATURE_ASYNC_PF_INT }, }; static int get_para_features(KVMState *s) @@ -2821,6 +2822,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level) if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) { kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr); } + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) { + kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, env->async_pf_int_msr); + } if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) { kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, env->pv_eoi_en_msr); } @@ -3206,6 +3210,9 @@ static int kvm_get_msrs(X86CPU *cpu) if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) { kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, 0); } + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) { + kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_INT, 0); + } if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) { kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, 0); } @@ -3446,6 +3453,9 @@ static int kvm_get_msrs(X86CPU *cpu) case MSR_KVM_ASYNC_PF_EN: env->async_pf_en_msr = msrs[i].data; break; + case MSR_KVM_ASYNC_PF_INT: + env->async_pf_int_msr = msrs[i].data; + break; case MSR_KVM_PV_EOI_EN: env->pv_eoi_en_msr = msrs[i].data; break; diff --git a/target/i386/machine.c b/target/i386/machine.c index b1acf7d0ef..233e46bb70 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -394,6 +394,13 @@ static bool async_pf_msr_needed(void *opaque) return cpu->env.async_pf_en_msr != 0; } +static bool async_pf_int_msr_needed(void *opaque) +{ + X86CPU *cpu = opaque; + + return cpu->env.async_pf_int_msr != 0; +} + static bool pv_eoi_msr_needed(void *opaque) { X86CPU *cpu = opaque; @@ -467,6 +474,17 @@ static const VMStateDescription vmstate_async_pf_msr = { } }; +static const VMStateDescription vmstate_async_pf_int_msr = { + .name = "cpu/async_pf_int_msr", + .version_id = 1, + .minimum_version_id = 1, + .needed = async_pf_int_msr_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.async_pf_int_msr, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_pv_eoi_msr = { .name = "cpu/async_pv_eoi_msr", .version_id = 1, @@ -1438,6 +1456,7 @@ VMStateDescription vmstate_x86_cpu = { .subsections = (const VMStateDescription*[]) { &vmstate_exception_info, &vmstate_async_pf_msr, + &vmstate_async_pf_int_msr, &vmstate_pv_eoi_msr, &vmstate_steal_time_msr, &vmstate_poll_control_msr, From ffb716f05015524cc97da18b34748961c743e827 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 8 Sep 2020 16:11:29 -0400 Subject: [PATCH 10/86] memory: Convert IOMMUMemoryRegionClass doc comment to kernel-doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the existing documentation comments of IOMMUMemoryRegionClass to kernel-doc format so their contents will appear in the API reference at docs/devel/memory.html. Signed-off-by: Eduardo Habkost Message-Id: <20200908201129.3407568-1-ehabkost@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 50 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 06b85e3a73..e22f5f5bb7 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -228,8 +228,11 @@ enum IOMMUMemoryRegionAttr { * attributes and the output TLB entry depends on the transaction * attributes, we represent this using IOMMU indexes. Each index * selects a particular translation table that the IOMMU has: + * * @attrs_to_index returns the IOMMU index for a set of transaction attributes + * * @translate takes an input address and an IOMMU index + * * and the mapping returned can only depend on the input address and the * IOMMU index. * @@ -238,10 +241,13 @@ enum IOMMUMemoryRegionAttr { * for secure transactions and one for non-secure transactions. */ struct IOMMUMemoryRegionClass { - /* private */ + /* private: */ MemoryRegionClass parent_class; - /* + /* public: */ + /** + * @translate: + * * Return a TLB entry that contains a given address. * * The IOMMUAccessFlags indicated via @flag are optional and may @@ -262,26 +268,38 @@ struct IOMMUMemoryRegionClass { * information when the IOMMU mapping changes. * * @iommu: the IOMMUMemoryRegion + * * @hwaddr: address to be translated within the memory region - * @flag: requested access permissions + * + * @flag: requested access permission + * * @iommu_idx: IOMMU index for the translation */ IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr, IOMMUAccessFlags flag, int iommu_idx); - /* Returns minimum supported page size in bytes. + /** + * @get_min_page_size: + * + * Returns minimum supported page size in bytes. + * * If this method is not provided then the minimum is assumed to * be TARGET_PAGE_SIZE. * * @iommu: the IOMMUMemoryRegion */ uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu); - /* Called when IOMMU Notifier flag changes (ie when the set of + /** + * @notify_flag_changed: + * + * Called when IOMMU Notifier flag changes (ie when the set of * events which IOMMU users are requesting notification for changes). * Optional method -- need not be provided if the IOMMU does not * need to know exactly which events must be notified. * * @iommu: the IOMMUMemoryRegion + * * @old_flags: events which previously needed to be notified + * * @new_flags: events which now need to be notified * * Returns 0 on success, or a negative errno; in particular @@ -293,7 +311,10 @@ struct IOMMUMemoryRegionClass { IOMMUNotifierFlag old_flags, IOMMUNotifierFlag new_flags, Error **errp); - /* Called to handle memory_region_iommu_replay(). + /** + * @replay: + * + * Called to handle memory_region_iommu_replay(). * * The default implementation of memory_region_iommu_replay() is to * call the IOMMU translate method for every page in the address space @@ -310,7 +331,10 @@ struct IOMMUMemoryRegionClass { */ void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier); - /* Get IOMMU misc attributes. This is an optional method that + /** + * @get_attr: + * + * Get IOMMU misc attributes. This is an optional method that * can be used to allow users of the IOMMU to get implementation-specific * information. The IOMMU implements this method to handle calls * by IOMMU users to memory_region_iommu_get_attr() by filling in @@ -319,7 +343,9 @@ struct IOMMUMemoryRegionClass { * memory_region_iommu_get_attr() will always return -EINVAL. * * @iommu: the IOMMUMemoryRegion + * * @attr: attribute being queried + * * @data: memory to fill in with the attribute data * * Returns 0 on success, or a negative errno; in particular @@ -328,7 +354,10 @@ struct IOMMUMemoryRegionClass { int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr, void *data); - /* Return the IOMMU index to use for a given set of transaction attributes. + /** + * @attrs_to_index: + * + * Return the IOMMU index to use for a given set of transaction attributes. * * Optional method: if an IOMMU only supports a single IOMMU index then * the default implementation of memory_region_iommu_attrs_to_index() @@ -341,7 +370,10 @@ struct IOMMUMemoryRegionClass { */ int (*attrs_to_index)(IOMMUMemoryRegion *iommu, MemTxAttrs attrs); - /* Return the number of IOMMU indexes this IOMMU supports. + /** + * @num_indexes: + * + * Return the number of IOMMU indexes this IOMMU supports. * * Optional method: if this method is not provided, then * memory_region_iommu_num_indexes() will return 1, indicating that From b82526c7ee484f2ba03944f804ab895aa75d89d3 Mon Sep 17 00:00:00 2001 From: Li Feng Date: Wed, 9 Sep 2020 20:20:21 +0800 Subject: [PATCH 11/86] vhost-scsi: support inflight io track Qemu will send GET_INFLIGHT_FD and SET_INFLIGH_FD to backend, and the backend setup the inflight memory to track the io. Change-Id: I805d6189996f7a1b44c65f0b12ef7473b1789510 Signed-off-by: Li Feng Message-Id: <20200909122021.1055174-1-fengli@smartx.com> Signed-off-by: Paolo Bonzini --- hw/scsi/vhost-scsi-common.c | 27 +++++++++++++++++++++++++++ include/hw/virtio/vhost-scsi-common.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c index 8ec49d7fef..767f827e55 100644 --- a/hw/scsi/vhost-scsi-common.c +++ b/hw/scsi/vhost-scsi-common.c @@ -32,6 +32,8 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIOSCSICommon *vs = (VirtIOSCSICommon *)vsc; + if (!k->set_guest_notifiers) { error_report("binding does not support guest notifiers"); return -ENOSYS; @@ -49,6 +51,23 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) } vsc->dev.acked_features = vdev->guest_features; + + assert(vsc->inflight == NULL); + vsc->inflight = g_new0(struct vhost_inflight, 1); + ret = vhost_dev_get_inflight(&vsc->dev, + vs->conf.virtqueue_size, + vsc->inflight); + if (ret < 0) { + error_report("Error get inflight: %d", -ret); + goto err_guest_notifiers; + } + + ret = vhost_dev_set_inflight(&vsc->dev, vsc->inflight); + if (ret < 0) { + error_report("Error set inflight: %d", -ret); + goto err_guest_notifiers; + } + ret = vhost_dev_start(&vsc->dev, vdev); if (ret < 0) { error_report("Error start vhost dev"); @@ -66,6 +85,9 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) return ret; err_guest_notifiers: + g_free(vsc->inflight); + vsc->inflight = NULL; + k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); err_host_notifiers: vhost_dev_disable_notifiers(&vsc->dev, vdev); @@ -89,6 +111,11 @@ void vhost_scsi_common_stop(VHostSCSICommon *vsc) } assert(ret >= 0); + if (vsc->inflight) { + vhost_dev_free_inflight(vsc->inflight); + vsc->inflight = NULL; + } + vhost_dev_disable_notifiers(&vsc->dev, vdev); } diff --git a/include/hw/virtio/vhost-scsi-common.h b/include/hw/virtio/vhost-scsi-common.h index 0c8909d12a..18f115527c 100644 --- a/include/hw/virtio/vhost-scsi-common.h +++ b/include/hw/virtio/vhost-scsi-common.h @@ -35,6 +35,8 @@ struct VHostSCSICommon { int lun; uint64_t host_features; bool migratable; + + struct vhost_inflight *inflight; }; int vhost_scsi_common_start(VHostSCSICommon *vsc); From 8f814ea1a2769311c71af069210dbba1de3aa9a4 Mon Sep 17 00:00:00 2001 From: Jon Doron Date: Wed, 15 Jul 2020 11:43:25 +0300 Subject: [PATCH 12/86] acpi: i386: Move VMBus DSDT entry to SB Signed-off-by: Jon Doron Reviewed-by: Igor Mammedov Message-Id: <20200715084326.678715-2-arilou@gmail.com> Signed-off-by: Paolo Bonzini --- hw/i386/acpi-build.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 8d14e4667a..45ad2f9533 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -990,7 +990,6 @@ static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) static void build_isa_devices_aml(Aml *table) { - VMBusBridge *vmbus_bridge = vmbus_bridge_find(); bool ambiguous; Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); Aml *scope; @@ -1001,10 +1000,6 @@ static void build_isa_devices_aml(Aml *table) build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA"); isa_build_aml(ISA_BUS(obj), scope); - if (vmbus_bridge) { - aml_append(scope, build_vmbus_device_aml(vmbus_bridge)); - } - aml_append(table, scope); } @@ -1500,6 +1495,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, PCIBus *bus = NULL; TPMIf *tpm = tpm_find(); int i; + VMBusBridge *vmbus_bridge = vmbus_bridge_find(); dsdt = init_aml_allocator(); @@ -1569,6 +1565,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } } + if (vmbus_bridge) { + sb_scope = aml_scope("_SB"); + aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge)); + aml_append(dsdt, sb_scope); + } + if (pcmc->legacy_cpu_hotplug) { build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base); } else { From b21aa7e01eb82f94ccdd7afdbe299a242d215272 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 11 Sep 2020 04:44:08 -0400 Subject: [PATCH 13/86] numa: drop support for '-numa node' (without memory specified) it was deprecated since 4.1 commit 4bb4a2732e (numa: deprecate implict memory distribution between nodes) Users of existing VMs, wishing to preserve the same RAM distribution, should configure it explicitly using ``-numa node,memdev`` options. Current RAM distribution can be retrieved using HMP command `info numa` and if separate memory devices (pc|nv-dimm) are present use `info memory-device` and subtract device memory from output of `info numa`. Signed-off-by: Igor Mammedov Message-Id: <20200911084410.788171-2-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- docs/system/deprecated.rst | 23 +++++++++------- hw/core/machine.c | 1 - hw/core/numa.c | 55 -------------------------------------- hw/i386/pc_piix.c | 1 - hw/i386/pc_q35.c | 1 - hw/ppc/spapr.c | 1 - include/hw/boards.h | 2 -- include/sysemu/numa.h | 4 --- 8 files changed, 14 insertions(+), 74 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 5326141cee..827482a8f7 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -92,15 +92,6 @@ error in the future. The ``-realtime mlock=on|off`` argument has been replaced by the ``-overcommit mem-lock=on|off`` argument. -``-numa`` node (without memory specified) (since 4.1) -''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Splitting RAM by default between NUMA nodes has the same issues as ``mem`` -parameter described above with the difference that the role of the user plays -QEMU using implicit generic or board specific splitting rule. -Use ``memdev`` with *memory-backend-ram* backend or ``mem`` (if -it's supported by used machine type) to define mapping explicitly instead. - ``-mem-path`` fallback to RAM (since 4.1) ''''''''''''''''''''''''''''''''''''''''' @@ -612,6 +603,20 @@ error when ``-u`` is not used. Command line options -------------------- +``-numa`` node (without memory specified) (removed 5.2) +''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Splitting RAM by default between NUMA nodes had the same issues as ``mem`` +parameter with the difference that the role of the user plays QEMU using +implicit generic or board specific splitting rule. +Use ``memdev`` with *memory-backend-ram* backend or ``mem`` (if +it's supported by used machine type) to define mapping explictly instead. +Users of existing VMs, wishing to preserve the same RAM distribution, should +configure it explicitly using ``-numa node,memdev`` options. Current RAM +distribution can be retrieved using HMP command ``info numa`` and if separate +memory devices (pc|nv-dimm) are present use ``info memory-device`` and subtract +device memory from output of ``info numa``. + ``-numa node,mem=``\ *size* (removed in 5.1) '''''''''''''''''''''''''''''''''''''''''''' diff --git a/hw/core/machine.c b/hw/core/machine.c index d7f4a0d259..7e2f4ec08e 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -790,7 +790,6 @@ static void machine_class_init(ObjectClass *oc, void *data) * On Linux, each node's border has to be 8MB aligned */ mc->numa_mem_align_shift = 23; - mc->numa_auto_assign_ram = numa_default_auto_assign_ram; object_class_property_add_str(oc, "kernel", machine_get_kernel, machine_set_kernel); diff --git a/hw/core/numa.c b/hw/core/numa.c index f9593ec716..706c1e84c6 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -611,42 +611,6 @@ static void complete_init_numa_distance(MachineState *ms) } } -void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes, - int nb_nodes, ram_addr_t size) -{ - int i; - uint64_t usedmem = 0; - - /* Align each node according to the alignment - * requirements of the machine class - */ - - for (i = 0; i < nb_nodes - 1; i++) { - nodes[i].node_mem = (size / nb_nodes) & - ~((1 << mc->numa_mem_align_shift) - 1); - usedmem += nodes[i].node_mem; - } - nodes[i].node_mem = size - usedmem; -} - -void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes, - int nb_nodes, ram_addr_t size) -{ - int i; - uint64_t usedmem = 0, node_mem; - uint64_t granularity = size / nb_nodes; - uint64_t propagate = 0; - - for (i = 0; i < nb_nodes - 1; i++) { - node_mem = (granularity + propagate) & - ~((1 << mc->numa_mem_align_shift) - 1); - propagate = granularity + propagate - node_mem; - nodes[i].node_mem = node_mem; - usedmem += node_mem; - } - nodes[i].node_mem = size - usedmem; -} - static void numa_init_memdev_container(MachineState *ms, MemoryRegion *ram) { int i; @@ -717,25 +681,6 @@ void numa_complete_configuration(MachineState *ms) ms->numa_state->num_nodes = MAX_NODES; } - /* If no memory size is given for any node, assume the default case - * and distribute the available memory equally across all nodes - */ - for (i = 0; i < ms->numa_state->num_nodes; i++) { - if (numa_info[i].node_mem != 0) { - break; - } - } - if (i == ms->numa_state->num_nodes) { - assert(mc->numa_auto_assign_ram); - mc->numa_auto_assign_ram(mc, numa_info, - ms->numa_state->num_nodes, ram_size); - if (!qtest_enabled()) { - warn_report("Default splitting of RAM between nodes is deprecated," - " Use '-numa node,memdev' to explictly define RAM" - " allocation per node"); - } - } - numa_total = 0; for (i = 0; i < ms->numa_state->num_nodes; i++) { numa_total += numa_info[i].node_mem; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2d8413a0ce..32c5d95762 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -565,7 +565,6 @@ static void pc_i440fx_2_9_machine_options(MachineClass *m) pc_i440fx_2_10_machine_options(m); compat_props_add(m->compat_props, hw_compat_2_9, hw_compat_2_9_len); compat_props_add(m->compat_props, pc_compat_2_9, pc_compat_2_9_len); - m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; } DEFINE_I440FX_MACHINE(v2_9, "pc-i440fx-2.9", NULL, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index e1c415f57d..e14d1446be 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -494,7 +494,6 @@ static void pc_q35_2_10_machine_options(MachineClass *m) pc_q35_2_11_machine_options(m); compat_props_add(m->compat_props, hw_compat_2_10, hw_compat_2_10_len); compat_props_add(m->compat_props, pc_compat_2_10, pc_compat_2_10_len); - m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; m->auto_enable_numa_with_memhp = false; } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index cbcd93b406..2db810f73a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4734,7 +4734,6 @@ static void spapr_machine_2_9_class_options(MachineClass *mc) spapr_machine_2_10_class_options(mc); compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len); compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); - mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram; smc->pre_2_10_has_unused_icps = true; smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; } diff --git a/include/hw/boards.h b/include/hw/boards.h index 482d2833f6..bf53e8a16e 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -202,8 +202,6 @@ struct MachineClass { strList *allowed_dynamic_sysbus_devices; bool auto_enable_numa_with_memhp; bool auto_enable_numa_with_memdev; - void (*numa_auto_assign_ram)(MachineClass *mc, NodeInfo *nodes, - int nb_nodes, ram_addr_t size); bool ignore_boot_device_suffixes; bool smbus_no_migration_support; bool nvdimm_supported; diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h index ad58ee88f7..4173ef2afa 100644 --- a/include/sysemu/numa.h +++ b/include/sysemu/numa.h @@ -106,10 +106,6 @@ void parse_numa_hmat_cache(MachineState *ms, NumaHmatCacheOptions *node, void numa_complete_configuration(MachineState *ms); void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms); extern QemuOptsList qemu_numa_opts; -void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes, - int nb_nodes, ram_addr_t size); -void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes, - int nb_nodes, ram_addr_t size); void numa_cpu_pre_plug(const struct CPUArchId *slot, DeviceState *dev, Error **errp); bool numa_uses_legacy_mem(void); From c01f250cb86cde926dbee4337317ccd58261fa1b Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 11 Sep 2020 04:44:09 -0400 Subject: [PATCH 14/86] doc: Cleanup "'-mem-path' fallback to RAM" deprecation text it was actually removed in 5.0, commit 68a86dc15c (numa: remove deprecated -mem-path fallback to anonymous RAM) clean up forgotten remnants in docs. Signed-off-by: Igor Mammedov Message-Id: <20200911084410.788171-3-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- docs/system/deprecated.rst | 43 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 827482a8f7..716f6aa315 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -92,17 +92,6 @@ error in the future. The ``-realtime mlock=on|off`` argument has been replaced by the ``-overcommit mem-lock=on|off`` argument. -``-mem-path`` fallback to RAM (since 4.1) -''''''''''''''''''''''''''''''''''''''''' - -Currently if guest RAM allocation from file pointed by ``mem-path`` -fails, QEMU falls back to allocating from RAM, which might result -in unpredictable behavior since the backing file specified by the user -is ignored. In the future, users will be responsible for making sure -the backing storage specified with ``-mem-path`` can actually provide -the guest RAM configured with ``-m`` and QEMU will fail to start up if -RAM allocation is unsuccessful. - RISC-V ``-bios`` (since 5.1) '''''''''''''''''''''''''''' @@ -603,6 +592,19 @@ error when ``-u`` is not used. Command line options -------------------- +``-smp`` (invalid topologies) (removed 5.2) +''''''''''''''''''''''''''''''''''''''''''' + +CPU topology properties should describe whole machine topology including +possible CPUs. + +However, historically it was possible to start QEMU with an incorrect topology +where *n* <= *sockets* * *cores* * *threads* < *maxcpus*, +which could lead to an incorrect topology enumeration by the guest. +Support for invalid topologies is removed, the user must ensure +topologies described with -smp include all possible cpus, i.e. +*sockets* * *cores* * *threads* = *maxcpus*. + ``-numa`` node (without memory specified) (removed 5.2) ''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -634,18 +636,15 @@ New machine versions (since 5.1) will not accept the option but it will still work with old machine types. User can check the QAPI schema to see if the legacy option is supported by looking at MachineInfo::numa-mem-supported property. -``-smp`` (invalid topologies) (removed 5.2) -''''''''''''''''''''''''''''''''''''''''''' +``-mem-path`` fallback to RAM (removed in 5.0) +'''''''''''''''''''''''''''''''''''''''''''''' -CPU topology properties should describe whole machine topology including -possible CPUs. - -However, historically it was possible to start QEMU with an incorrect topology -where *n* <= *sockets* * *cores* * *threads* < *maxcpus*, -which could lead to an incorrect topology enumeration by the guest. -Support for invalid topologies is removed, the user must ensure -topologies described with -smp include all possible cpus, i.e. -*sockets* * *cores* * *threads* = *maxcpus*. +If guest RAM allocation from file pointed by ``mem-path`` failed, +QEMU was falling back to allocating from RAM, which might have resulted +in unpredictable behavior since the backing file specified by the user +as ignored. Currently, users are responsible for making sure the backing storage +specified with ``-mem-path`` can actually provide the guest RAM configured with +``-m`` and QEMU fails to start up if RAM allocation is unsuccessful. Block devices ------------- From 270b33cc1c40ce2eff1abdf67b04fc008167b525 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 11 Sep 2020 04:44:10 -0400 Subject: [PATCH 15/86] numa: remove fixup numa_state->num_nodes to MAX_NODES current code permits only nodeids in [0..MAX_NODES) range due to nodeid check in parse_numa_node() if (nodenr >= MAX_NODES) { error_setg(errp, "Max number of NUMA nodes reached: %" so subj fixup is not reachable, drop it. Signed-off-by: Igor Mammedov Message-Id: <20200911084410.788171-4-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/numa.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/core/numa.c b/hw/core/numa.c index 706c1e84c6..7d5d413001 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -677,10 +677,6 @@ void numa_complete_configuration(MachineState *ms) if (ms->numa_state->num_nodes > 0) { uint64_t numa_total; - if (ms->numa_state->num_nodes > MAX_NODES) { - ms->numa_state->num_nodes = MAX_NODES; - } - numa_total = 0; for (i = 0; i < ms->numa_state->num_nodes; i++) { numa_total += numa_info[i].node_mem; From cf3d932f97d4f76339846f49075fecca690308ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:15:37 +0200 Subject: [PATCH 16/86] hw/mips/mipssim: Use MMIO serial device on fake ISA I/O MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'mipssim' is not a real hardware, it is a simulator. There is an ISA MMIO space mapped at 0x1fd00000, however this is not a real ISA bus (no ISA IRQ). So can not use the TYPE_ISA_SERIAL device... Instead we have been using a plain MMIO device, but named it IO. TYPE_SERIAL_IO is a subset of TYPE_SERIAL_MM, using regshift=0 and endianness=DEVICE_LITTLE_ENDIAN. Directly use the TYPE_SERIAL_MM device, enforcing the regshift/endianness values. 'regshift' default is already '0'. 'endianness' is meaningless for 8-bit accesses. This change breaks migration back compatibility, but this is not an issue for the mipssim machine. Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200907011538.818996-2-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- hw/mips/mipssim.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index 1b3b762203..5d4ad74828 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -216,10 +216,11 @@ mips_mipssim_init(MachineState *machine) * MIPS CPU INT2, which is interrupt 4. */ if (serial_hd(0)) { - DeviceState *dev = qdev_new(TYPE_SERIAL_IO); + DeviceState *dev = qdev_new(TYPE_SERIAL_MM); qdev_prop_set_chr(dev, "chardev", serial_hd(0)); - qdev_set_legacy_instance_id(dev, 0x3f8, 2); + qdev_prop_set_uint8(dev, "regshift", 0); + qdev_prop_set_uint8(dev, "endianness", DEVICE_LITTLE_ENDIAN); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, env->irq[4]); sysbus_add_io(SYS_BUS_DEVICE(dev), 0x3f8, From 08516115303c0b72690b3f3ea80149f7a18f961f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:15:38 +0200 Subject: [PATCH 17/86] hw/char/serial: Remove TYPE_SERIAL_IO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TYPE_SERIAL_IO is a subset of TYPE_SERIAL_MM, and it is not used anymore. Remove it. Suggested-by: Paolo Bonzini Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200907011538.818996-3-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- hw/char/serial.c | 41 ---------------------------------------- include/hw/char/serial.h | 9 --------- 2 files changed, 50 deletions(-) diff --git a/hw/char/serial.c b/hw/char/serial.c index 2386479492..fd80ae5592 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -985,46 +985,6 @@ const MemoryRegionOps serial_io_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void serial_io_realize(DeviceState *dev, Error **errp) -{ - SerialIO *sio = SERIAL_IO(dev); - SerialState *s = &sio->serial; - - if (!qdev_realize(DEVICE(s), NULL, errp)) { - return; - } - - memory_region_init_io(&s->io, OBJECT(dev), &serial_io_ops, s, "serial", 8); - sysbus_init_mmio(SYS_BUS_DEVICE(sio), &s->io); - sysbus_init_irq(SYS_BUS_DEVICE(sio), &s->irq); -} - -static void serial_io_class_init(ObjectClass *klass, void* data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = serial_io_realize; - /* No dc->vmsd: class has no migratable state */ -} - -static void serial_io_instance_init(Object *o) -{ - SerialIO *sio = SERIAL_IO(o); - - object_initialize_child(o, "serial", &sio->serial, TYPE_SERIAL); - - qdev_alias_all_properties(DEVICE(&sio->serial), o); -} - - -static const TypeInfo serial_io_info = { - .name = TYPE_SERIAL_IO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SerialIO), - .instance_init = serial_io_instance_init, - .class_init = serial_io_class_init, -}; - static Property serial_properties[] = { DEFINE_PROP_CHR("chardev", SerialState, chr), DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200), @@ -1178,7 +1138,6 @@ static const TypeInfo serial_mm_info = { static void serial_register_types(void) { type_register_static(&serial_info); - type_register_static(&serial_io_info); type_register_static(&serial_mm_info); } diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h index db4f9af18c..23bd7d3dde 100644 --- a/include/hw/char/serial.h +++ b/include/hw/char/serial.h @@ -90,12 +90,6 @@ struct SerialMM { uint8_t endianness; }; -struct SerialIO { - SysBusDevice parent; - - SerialState serial; -}; - extern const VMStateDescription vmstate_serial; extern const MemoryRegionOps serial_io_ops; @@ -107,9 +101,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(SerialState, SERIAL) #define TYPE_SERIAL_MM "serial-mm" OBJECT_DECLARE_SIMPLE_TYPE(SerialMM, SERIAL_MM) -#define TYPE_SERIAL_IO "serial-io" -OBJECT_DECLARE_SIMPLE_TYPE(SerialIO, SERIAL_IO) - SerialMM *serial_mm_init(MemoryRegion *address_space, hwaddr base, int regshift, qemu_irq irq, int baudbase, From 4bad7c3b58526611accd9238c1e70898de5e5255 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 14 Sep 2020 10:52:31 +0100 Subject: [PATCH 18/86] configure: rename QEMU_GA_MSI_ENABLED to CONFIG_QGA_MSI The QEMU_GA_MSI_ENABLED config-host.mak variable is emitted by ./configure. meson.build actually checks for CONFIG_QGA_MSI_ENABLED: summary_info += {'QGA MSI support': config_host.has_key('CONFIG_QGA_MSI_ENABLED')} Rename QEMU_GA_MSI_ENABLED to CONFIG_QGA_MSI for consistency with CONFIG_QGA_VSS. Also use 'y' instead of 'yes' for consistency. This fixes the feature summary printed by meson.build. Signed-off-by: Stefan Hajnoczi Message-Id: <20200914095231.621068-4-stefanha@redhat.com> Signed-off-by: Paolo Bonzini --- Makefile | 2 +- configure | 2 +- meson.build | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 7b2655db08..9af24f1e8c 100644 --- a/Makefile +++ b/Makefile @@ -285,7 +285,7 @@ endif ifdef CONFIG_WIN32 @echo 'Windows targets:' $(call print-help,installer,Build NSIS-based installer for QEMU) -ifdef QEMU_GA_MSI_ENABLED +ifdef CONFIG_QGA_MSI $(call print-help,msi,Build MSI-based installer for qemu-ga) endif @echo '' diff --git a/configure b/configure index 9e1989976f..f9e2f3de65 100755 --- a/configure +++ b/configure @@ -6570,7 +6570,7 @@ if test "$mingw32" = "yes" ; then echo "CONFIG_QGA_NTDDSCSI=y" >> $config_host_mak fi if test "$guest_agent_msi" = "yes"; then - echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak + echo "CONFIG_QGA_MSI=y" >> $config_host_mak echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak echo "QEMU_GA_MSI_WITH_VSS=${QEMU_GA_MSI_WITH_VSS}" >> $config_host_mak echo "QEMU_GA_MSI_ARCH=${QEMU_GA_MSI_ARCH}" >> $config_host_mak diff --git a/meson.build b/meson.build index 9755be79fd..975a187e2c 100644 --- a/meson.build +++ b/meson.build @@ -1412,7 +1412,7 @@ if targetos == 'windows' endif summary_info += {'QGA VSS support': config_host.has_key('CONFIG_QGA_VSS')} summary_info += {'QGA w32 disk info': config_host.has_key('CONFIG_QGA_NTDDSCSI')} - summary_info += {'QGA MSI support': config_host.has_key('CONFIG_QGA_MSI_ENABLED')} + summary_info += {'QGA MSI support': config_host.has_key('CONFIG_QGA_MSI')} endif summary_info += {'seccomp support': config_host.has_key('CONFIG_SECCOMP')} summary_info += {'coroutine backend': config_host['CONFIG_COROUTINE_BACKEND']} From 6ab9be1ec1267865c2f4c334668e05f5810b8836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:55:29 +0200 Subject: [PATCH 19/86] hw/char/serial: Assert serial_ioport_read/write offset fits 8 bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The serial device has 8 registers, each 8-bit. The MemoryRegionOps 'serial_io_ops' is initialized with max_access_size=1, and all memory_region_init_io() callers correctly set the region size to 8 bytes: - serial_io_realize - serial_isa_realizefn - serial_pci_realize - multi_serial_pci_realize It is safe to assert the offset argument of serial_ioport_read() and serial_ioport_write() is always less than 8. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200907015535.827885-2-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/char/serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/char/serial.c b/hw/char/serial.c index fd80ae5592..840da89de7 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -344,7 +344,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, { SerialState *s = opaque; - addr &= 7; + assert(size == 1 && addr < 8); trace_serial_ioport_write(addr, val); switch(addr) { default: @@ -485,7 +485,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) SerialState *s = opaque; uint32_t ret; - addr &= 7; + assert(size == 1 && addr < 8); switch(addr) { default: case 0: From 4d7b9a6373504cd75a589775fee9debf76912d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:55:30 +0200 Subject: [PATCH 20/86] hw/char/serial: Replace commented DPRINTF() by trace event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the old debug PRINTF() call to display the UART baudrate to a trace event. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200907015535.827885-3-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/char/serial.c | 4 +--- hw/char/trace-events | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/char/serial.c b/hw/char/serial.c index 840da89de7..e8029f840a 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -187,9 +187,7 @@ static void serial_update_parameters(SerialState *s) ssp.stop_bits = stop_bits; s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); - - DPRINTF("speed=%.2f parity=%c data=%d stop=%d\n", - speed, parity, data_bits, stop_bits); + trace_serial_update_parameters(speed, parity, data_bits, stop_bits); } static void serial_update_msl(SerialState *s) diff --git a/hw/char/trace-events b/hw/char/trace-events index 2442a9f7d5..17304bef26 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -7,6 +7,7 @@ parallel_ioport_write(const char *desc, uint16_t addr, uint8_t value) "write [%s # serial.c serial_ioport_read(uint16_t addr, uint8_t value) "read addr 0x%02x val 0x%02x" serial_ioport_write(uint16_t addr, uint8_t value) "write addr 0x%02x val 0x%02x" +serial_update_parameters(uint64_t baudrate, char parity, int data_bits, int stop_bits) "baudrate=%"PRIu64" parity='%c' data=%d stop=%d" # virtio-serial-bus.c virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u" From 1acb1fe1665b68f226943bbd2919c630b7e0344c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:55:31 +0200 Subject: [PATCH 21/86] hw/char/serial: Remove old DEBUG_SERIAL commented code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All useful DPRINTF() calls have been converted to trace events. Remove a pointless one in the IOEventHandler, and drop the DEBUG_SERIAL ifdef'ry. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200907015535.827885-4-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/char/serial.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/char/serial.c b/hw/char/serial.c index e8029f840a..26f7fa8a21 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -36,8 +36,6 @@ #include "trace.h" #include "hw/qdev-properties.h" -//#define DEBUG_SERIAL - #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ #define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ @@ -102,14 +100,6 @@ #define MAX_XMIT_RETRY 4 -#ifdef DEBUG_SERIAL -#define DPRINTF(fmt, ...) \ -do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ -do {} while (0) -#endif - static void serial_receive1(void *opaque, const uint8_t *buf, int size); static void serial_xmit(SerialState *s); @@ -636,7 +626,6 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) static void serial_event(void *opaque, QEMUChrEvent event) { SerialState *s = opaque; - DPRINTF("event %x\n", event); if (event == CHR_EVENT_BREAK) serial_receive_break(s); } From f2336b5fbdfcf0aef9a66e4b170648e10faf7a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:55:32 +0200 Subject: [PATCH 22/86] hw/char/serial: Rename I/O read/write trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The serial_mm_read/write() handlers from the TYPE_SERIAL_MM device call the serial_ioport_read/write() handlers with shifted offset. When looking at the trace events from this MMIO device, it is confusing to read the accesses as I/O. Simplify using generic trace event names which make sense the various uses. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200907015535.827885-5-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/char/serial.c | 4 ++-- hw/char/trace-events | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/char/serial.c b/hw/char/serial.c index 26f7fa8a21..7b5ef872bd 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -333,7 +333,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, SerialState *s = opaque; assert(size == 1 && addr < 8); - trace_serial_ioport_write(addr, val); + trace_serial_write(addr, val); switch(addr) { default: case 0: @@ -550,7 +550,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) ret = s->scr; break; } - trace_serial_ioport_read(addr, ret); + trace_serial_read(addr, ret); return ret; } diff --git a/hw/char/trace-events b/hw/char/trace-events index 17304bef26..609df10fed 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -5,8 +5,8 @@ parallel_ioport_read(const char *desc, uint16_t addr, uint8_t value) "read [%s] parallel_ioport_write(const char *desc, uint16_t addr, uint8_t value) "write [%s] addr 0x%02x val 0x%02x" # serial.c -serial_ioport_read(uint16_t addr, uint8_t value) "read addr 0x%02x val 0x%02x" -serial_ioport_write(uint16_t addr, uint8_t value) "write addr 0x%02x val 0x%02x" +serial_read(uint16_t addr, uint8_t value) "read addr 0x%02x val 0x%02x" +serial_write(uint16_t addr, uint8_t value) "write addr 0x%02x val 0x%02x" serial_update_parameters(uint64_t baudrate, char parity, int data_bits, int stop_bits) "baudrate=%"PRIu64" parity='%c' data=%d stop=%d" # virtio-serial-bus.c From 1fa2c0eb6c7e5a5cf714c2a9dfea7633429af76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:55:33 +0200 Subject: [PATCH 23/86] hw/char/serial: Make 'wakeup' property boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the "wakeup" property introduced in commit 9826fd597df ("suspend: make serial ports wakeup the guest") a boolean. As we want to reuse the generic serial properties in the ISA model (next commit), expose this property. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200907015535.827885-6-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/char/serial-isa.c | 2 +- hw/char/serial.c | 1 + include/hw/char/serial.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index 32c2fc0ebe..fc8ff7823a 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -117,7 +117,7 @@ static Property serial_isa_properties[] = { DEFINE_PROP_UINT32("iobase", ISASerialState, iobase, -1), DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), - DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0), + DEFINE_PROP_BOOL("wakeup", ISASerialState, state.wakeup, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/char/serial.c b/hw/char/serial.c index 7b5ef872bd..4386adabd4 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -975,6 +975,7 @@ const MemoryRegionOps serial_io_ops = { static Property serial_properties[] = { DEFINE_PROP_CHR("chardev", SerialState, chr), DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200), + DEFINE_PROP_BOOL("wakeup", SerialState, wakeup, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h index 23bd7d3dde..8ba7eca3d6 100644 --- a/include/hw/char/serial.h +++ b/include/hw/char/serial.h @@ -61,7 +61,7 @@ struct SerialState { uint32_t baudbase; uint32_t tsr_retry; guint watch_tag; - uint32_t wakeup; + bool wakeup; /* Time when the last byte was successfully sent out of the tsr */ uint64_t last_xmit_ts; From b7dd40d40bfa44536bee4aa4d643b26621097d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 7 Sep 2020 03:55:34 +0200 Subject: [PATCH 24/86] hw/char/serial-{isa, pci}: Alias QDEV properties from generic serial object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of overwritting the properties of the generic 'state' object, alias them. Note we can now propagate the "baudbase" property. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20200907015535.827885-7-f4bug@amsat.org> Signed-off-by: Paolo Bonzini --- hw/char/serial-isa.c | 4 ++-- hw/char/serial-pci.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index fc8ff7823a..1b8b303079 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -116,8 +116,6 @@ static Property serial_isa_properties[] = { DEFINE_PROP_UINT32("index", ISASerialState, index, -1), DEFINE_PROP_UINT32("iobase", ISASerialState, iobase, -1), DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), - DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), - DEFINE_PROP_BOOL("wakeup", ISASerialState, state.wakeup, false), DEFINE_PROP_END_OF_LIST(), }; @@ -138,6 +136,8 @@ static void serial_isa_initfn(Object *o) ISASerialState *self = ISA_SERIAL(o); object_initialize_child(o, "serial", &self->state, TYPE_SERIAL); + + qdev_alias_all_properties(DEVICE(&self->state), o); } static const TypeInfo serial_isa_info = { diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index b0520a5a09..93d6f99244 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -82,7 +82,6 @@ static const VMStateDescription vmstate_pci_serial = { }; static Property serial_pci_properties[] = { - DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02), DEFINE_PROP_END_OF_LIST(), }; @@ -107,6 +106,8 @@ static void serial_pci_init(Object *o) PCISerialState *ps = PCI_SERIAL(o); object_initialize_child(o, "serial", &ps->state, TYPE_SERIAL); + + qdev_alias_all_properties(DEVICE(&ps->state), o); } static const TypeInfo serial_pci_info = { From afff2db61f6ace9bb2c4d81c7c57601f5c009acd Mon Sep 17 00:00:00 2001 From: Dmitry Fomichev Date: Wed, 12 Aug 2020 07:51:22 +0900 Subject: [PATCH 25/86] scsi-generic: Fix HM-zoned device scan Several important steps during device scan depend on SCSI type of the device. For example, max_transfer property is only determined and assigned if the device has the type of TYPE_DISK. Host-managed ZBC disks retain most of the properties of regular SCSI drives, but they have their own SCSI device type, 0x14. This prevents the proper assignment of max_transfer property for HM-zoned devices in scsi-generic driver leading to I/O errors if the maximum i/o size calculated at the guest exceeds the host value. To fix this, define TYPE_ZBC to have the standard value from SCSI ZBC standard spec. Several scan steps that were previously done only for TYPE_DISK devices, are now performed for the SCSI devices having TYPE_ZBC too. Reported-by: Johannes Thumshirn Signed-off-by: Dmitry Fomichev Message-Id: <20200811225122.17342-3-dmitry.fomichev@wdc.com> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-generic.c | 10 ++++++---- include/scsi/constants.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 86ed0a3822..2cb23ca891 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -162,7 +162,8 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) } } - if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) { + if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) && + (r->req.cmd.buf[1] & 0x01)) { page = r->req.cmd.buf[2]; if (page == 0xb0) { uint32_t max_transfer = @@ -299,10 +300,11 @@ static void scsi_read_complete(void * opaque, int ret) } blk_set_guest_block_size(s->conf.blk, s->blocksize); - /* Patch MODE SENSE device specific parameters if the BDS is opened + /* + * Patch MODE SENSE device specific parameters if the BDS is opened * readonly. */ - if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) && + if ((s->type == TYPE_DISK || s->type == TYPE_TAPE || s->type == TYPE_ZBC) && blk_is_read_only(s->conf.blk) && (r->req.cmd.buf[0] == MODE_SENSE || r->req.cmd.buf[0] == MODE_SENSE_10) && @@ -617,7 +619,7 @@ static void scsi_generic_read_device_identification(SCSIDevice *s) void scsi_generic_read_device_inquiry(SCSIDevice *s) { scsi_generic_read_device_identification(s); - if (s->type == TYPE_DISK) { + if (s->type == TYPE_DISK || s->type == TYPE_ZBC) { scsi_generic_set_vpd_bl_emulation(s); } else { s->needs_vpd_bl_emulation = false; diff --git a/include/scsi/constants.h b/include/scsi/constants.h index 874176019e..2a32c08b5e 100644 --- a/include/scsi/constants.h +++ b/include/scsi/constants.h @@ -218,6 +218,7 @@ #define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ #define TYPE_RBC 0x0e /* Simplified Direct-Access Device */ #define TYPE_OSD 0x11 /* Object-storage Device */ +#define TYPE_ZBC 0x14 /* Host-managed Zoned SCSI Device */ #define TYPE_WLUN 0x1e /* Well known LUN */ #define TYPE_NOT_PRESENT 0x1f #define TYPE_INACTIVE 0x20 From 5ecfbae201d68a2f13df233260c77b0a25d7cd35 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Sat, 15 Aug 2020 07:19:39 -0700 Subject: [PATCH 26/86] hw: megasas: return -1 when 'megasas_map_sgl' fails The caller of 'megasas_map_sgl' will only check if the return is zero or not. If it return 0 it means success, as in the next patch we will consider 'iov_count=0' is an error, so let's return -1 to indicate a failure. Signed-off-by: Li Qiang Message-Id: <20200815141940.44025-2-liq3ea@163.com> Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index e90c00823a..4cc709d2c6 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -280,7 +280,7 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl) if (iov_count > MEGASAS_MAX_SGE) { trace_megasas_iovec_sgl_overflow(cmd->index, iov_count, MEGASAS_MAX_SGE); - return iov_count; + return -1; } pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), iov_count); for (i = 0; i < iov_count; i++) { @@ -310,7 +310,7 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl) return 0; unmap: qemu_sglist_destroy(&cmd->qsg); - return iov_count - i; + return -1; } /* From 4773a5f35b0d83674f92816a226a594b03bbcf60 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Sat, 15 Aug 2020 07:19:40 -0700 Subject: [PATCH 27/86] hw: megasas: consider 'iov_count=0' is an error in megasas_map_sgl Currently in 'megasas_map_sgl' when 'iov_count=0' will just return success however the 'cmd' doens't contain any iov. This will cause the assert in 'scsi_dma_complete' failed. This is because in 'dma_blk_cb' the 'dbs->sg_cur_index == dbs->sg->nsg' will be true and just call 'dma_complete'. However now there is no aiocb returned. This fixes the LP#1878263: -->https://bugs.launchpad.net/qemu/+bug/1878263 Reported-by: Alexander Bulekov Signed-off-by: Li Qiang Message-Id: <20200815141940.44025-3-liq3ea@163.com> Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 4cc709d2c6..e24c12d7ee 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -277,7 +277,7 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl) cmd->flags = le16_to_cpu(cmd->frame->header.flags); iov_count = cmd->frame->header.sge_count; - if (iov_count > MEGASAS_MAX_SGE) { + if (!iov_count || iov_count > MEGASAS_MAX_SGE) { trace_megasas_iovec_sgl_overflow(cmd->index, iov_count, MEGASAS_MAX_SGE); return -1; From 19ca8285fcd61a8f60f2f44f789a561e0958e8e6 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 16 Jul 2020 16:20:18 +0800 Subject: [PATCH 28/86] i386/cpu: Clear FEAT_XSAVE_COMP_{LO,HI} when XSAVE is not available Per Intel SDM vol 1, 13.2, if CPUID.1:ECX.XSAVE[bit 26] is 0, the processor provides no further enumeration through CPUID function 0DH. QEMU does not do this for "-cpu host,-xsave". Signed-off-by: Xiaoyao Li Message-Id: <20200716082019.215316-2-xiaoyao.li@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 0ea0630e1f..f37eb7b675 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6267,6 +6267,8 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) uint64_t mask; if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { + env->features[FEAT_XSAVE_COMP_LO] = 0; + env->features[FEAT_XSAVE_COMP_HI] = 0; return; } From f01496a314d916949ef84426d6cdd34f50447bb7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 16 Sep 2020 17:54:14 +0200 Subject: [PATCH 29/86] meson: move libudev test Signed-off-by: Paolo Bonzini --- configure | 14 -------------- meson.build | 7 ++++--- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/configure b/configure index f9e2f3de65..6f2599f99f 100755 --- a/configure +++ b/configure @@ -908,7 +908,6 @@ Linux) linux_user="yes" kvm="yes" QEMU_INCLUDES="-isystem ${source_path}/linux-headers -Ilinux-headers $QEMU_INCLUDES" - libudev="yes" ;; esac @@ -6287,15 +6286,6 @@ if test "$libnfs" != "no" ; then fi ########################################## -# Do we have libudev -if test "$libudev" != "no" ; then - if $pkg_config libudev && test "$static" != "yes"; then - libudev="yes" - libudev_libs=$($pkg_config --libs libudev) - else - libudev="no" - fi -fi # Exclude --warn-common with TSan to suppress warnings from the TSan libraries. if test "$solaris" = "no" && test "$tsan" = "no"; then @@ -7456,10 +7446,6 @@ if test "$gcov" = "yes" ; then echo "CONFIG_GCOV=y" >> $config_host_mak fi -if test "$libudev" != "no"; then - echo "CONFIG_LIBUDEV=y" >> $config_host_mak - echo "LIBUDEV_LIBS=$libudev_libs" >> $config_host_mak -fi if test "$fuzzing" != "no"; then echo "CONFIG_FUZZ=y" >> $config_host_mak fi diff --git a/meson.build b/meson.build index 975a187e2c..cd3d1ee260 100644 --- a/meson.build +++ b/meson.build @@ -257,8 +257,8 @@ if 'CONFIG_CURL' in config_host link_args: config_host['CURL_LIBS'].split()) endif libudev = not_found -if 'CONFIG_LIBUDEV' in config_host - libudev = declare_dependency(link_args: config_host['LIBUDEV_LIBS'].split()) +if targetos == 'linux' and (have_system or have_tools) + libudev = dependency('libudev', static: enable_static) endif brlapi = not_found if 'CONFIG_BRLAPI' in config_host @@ -440,6 +440,7 @@ has_gettid = cc.has_function('gettid') # Create config-host.h +config_host_data.set('CONFIG_LIBUDEV', libudev.found()) config_host_data.set('CONFIG_SDL', sdl.found()) config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found()) config_host_data.set('CONFIG_VNC', vnc.found()) @@ -1450,7 +1451,7 @@ summary_info += {'sheepdog support': config_host.has_key('CONFIG_SHEEPDOG')} summary_info += {'capstone': config_host.has_key('CONFIG_CAPSTONE')} summary_info += {'libpmem support': config_host.has_key('CONFIG_LIBPMEM')} summary_info += {'libdaxctl support': config_host.has_key('CONFIG_LIBDAXCTL')} -summary_info += {'libudev': config_host.has_key('CONFIG_LIBUDEV')} +summary_info += {'libudev': libudev.found()} summary_info += {'default devices': config_host['CONFIG_MINIKCONF_MODE'] == '--defconfig'} summary_info += {'plugin support': config_host.has_key('CONFIG_PLUGIN')} summary_info += {'fuzzing support': config_host.has_key('CONFIG_FUZZ')} From 6ec0e15d95da4e80bc890933e3e5bc11f6b54118 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 16 Sep 2020 18:07:29 +0200 Subject: [PATCH 30/86] meson: move libmpathpersist test This is the first compiler/linker test that has been moved to Meson. Add more section headings to keep things clearer. This also fixes static linking to libmpathpersist, which has a dependency on libmultipath but no pkg-config file to describe it. Signed-off-by: Paolo Bonzini --- configure | 77 +++----------------------------------------- meson.build | 81 +++++++++++++++++++++++++++++++++++++++++++---- meson_options.txt | 2 ++ 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/configure b/configure index 6f2599f99f..aade6eb285 100755 --- a/configure +++ b/configure @@ -403,7 +403,7 @@ netmap="no" sdl="auto" sdl_image="auto" virtfs="" -mpath="" +mpath="auto" vnc="enabled" sparse="no" vde="" @@ -1116,9 +1116,9 @@ for opt do ;; --enable-virtfs) virtfs="yes" ;; - --disable-mpath) mpath="no" + --disable-mpath) mpath="disabled" ;; - --enable-mpath) mpath="yes" + --enable-mpath) mpath="enabled" ;; --disable-vnc) vnc="disabled" ;; @@ -3852,57 +3852,6 @@ if test "$modules" = yes; then fi fi -########################################## -# libmpathpersist probe - -if test "$mpath" != "no" ; then - # probe for the new API - cat > $TMPC < -#include -unsigned mpath_mx_alloc_len = 1024; -int logsink; -static struct config *multipath_conf; -extern struct udev *udev; -extern struct config *get_multipath_config(void); -extern void put_multipath_config(struct config *conf); -struct udev *udev; -struct config *get_multipath_config(void) { return multipath_conf; } -void put_multipath_config(struct config *conf) { } - -int main(void) { - udev = udev_new(); - multipath_conf = mpath_lib_init(); - return 0; -} -EOF - if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then - mpathpersist=yes - mpathpersist_new_api=yes - else - # probe for the old API - cat > $TMPC < -#include -unsigned mpath_mx_alloc_len = 1024; -int logsink; -int main(void) { - struct udev *udev = udev_new(); - mpath_lib_init(udev); - return 0; -} -EOF - if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then - mpathpersist=yes - mpathpersist_new_api=no - else - mpathpersist=no - fi - fi -else - mpathpersist=no -fi - ########################################## # pthread probe PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2" @@ -6337,23 +6286,11 @@ if test "$softmmu" = yes ; then fi virtfs=no fi - if test "$mpath" != no && test "$mpathpersist" = yes ; then - mpath=yes - else - if test "$mpath" = yes; then - error_exit "Multipath requires libmpathpersist devel" - fi - mpath=no - fi else if test "$virtfs" = yes; then error_exit "VirtFS is supported only on Linux" fi virtfs=no - if test "$mpath" = yes; then - error_exit "Multipath is supported only on Linux" - fi - mpath=no fi fi @@ -6894,12 +6831,6 @@ fi if test "$virtfs" = "yes" ; then echo "CONFIG_VIRTFS=y" >> $config_host_mak fi -if test "$mpath" = "yes" ; then - echo "CONFIG_MPATH=y" >> $config_host_mak - if test "$mpathpersist_new_api" = "yes"; then - echo "CONFIG_MPATH_NEW_API=y" >> $config_host_mak - fi -fi if test "$vhost_scsi" = "yes" ; then echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak fi @@ -7988,7 +7919,7 @@ NINJA=${ninja:-$PWD/ninjatool} $meson setup \ -Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \ -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ - -Dsdl=$sdl -Dsdl_image=$sdl_image \ + -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \ -Dvnc=$vnc -Dvnc_sasl=$vnc_sasl -Dvnc_jpeg=$vnc_jpeg -Dvnc_png=$vnc_png \ -Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f\ $cross_arg \ diff --git a/meson.build b/meson.build index cd3d1ee260..8e9cd67235 100644 --- a/meson.build +++ b/meson.build @@ -86,6 +86,14 @@ if 'SPARSE_CFLAGS' in config_host 'compile_commands.json']) endif +########################################### +# Target-specific checks and dependencies # +########################################### + +if targetos != 'linux' and get_option('mpath').enabled() + error('Multipath is supported only on Linux') +endif + m = cc.find_library('m', required: false) util = cc.find_library('util', required: false) winmm = [] @@ -117,6 +125,11 @@ elif targetos == 'haiku' cc.find_library('network'), cc.find_library('bsd')] endif + +################ +# Dependencies # +################ + # The path to glib.h is added to all compilation commands. This was # grandfathered in from the QEMU Makefiles. add_project_arguments(config_host['GLIB_CFLAGS'].split(), @@ -223,10 +236,6 @@ if 'CONFIG_SPICE' in config_host link_args: config_host['SPICE_LIBS'].split()) endif rt = cc.find_library('rt', required: false) -libmpathpersist = not_found -if config_host.has_key('CONFIG_MPATH') - libmpathpersist = cc.find_library('mpathpersist') -endif libdl = not_found if 'CONFIG_PLUGIN' in config_host libdl = cc.find_library('dl', required: true) @@ -258,8 +267,64 @@ if 'CONFIG_CURL' in config_host endif libudev = not_found if targetos == 'linux' and (have_system or have_tools) - libudev = dependency('libudev', static: enable_static) + libudev = dependency('libudev', + required: get_option('mpath').enabled(), + static: enable_static) endif + +mpathpersist = not_found +mpathpersist_new_api = false +if targetos == 'linux' and have_tools and not get_option('mpath').disabled() + mpath_test_source_new = ''' + #include + #include + unsigned mpath_mx_alloc_len = 1024; + int logsink; + static struct config *multipath_conf; + extern struct udev *udev; + extern struct config *get_multipath_config(void); + extern void put_multipath_config(struct config *conf); + struct udev *udev; + struct config *get_multipath_config(void) { return multipath_conf; } + void put_multipath_config(struct config *conf) { } + int main(void) { + udev = udev_new(); + multipath_conf = mpath_lib_init(); + return 0; + }''' + mpath_test_source_old = ''' + #include + #include + unsigned mpath_mx_alloc_len = 1024; + int logsink; + int main(void) { + struct udev *udev = udev_new(); + mpath_lib_init(udev); + return 0; + }''' + libmultipath = cc.find_library('multipath', + required: get_option('mpath'), + static: enable_static) + libmpathpersist = cc.find_library('mpathpersist', + required: get_option('mpath'), + static: enable_static) + if libmultipath.found() and libmpathpersist.found() and libudev.found() + mpathlibs = [libmultipath, libmpathpersist, libudev] + if cc.links(mpath_test_source_new, dependencies: mpathlibs) + mpathpersist = declare_dependency(dependencies: mpathlibs) + mpathpersist_new_api = true + elif cc.links(mpath_test_source_old, dependencies: mpathlibs) + mpathpersist = declare_dependency(dependencies: mpathlibs) + else + if get_option('mpath').enabled() + error('Cannot detect libmpathpersist API') + else + warning('Cannot detect libmpathpersist API, disabling') + endif + endif + endif +endif + brlapi = not_found if 'CONFIG_BRLAPI' in config_host brlapi = declare_dependency(link_args: config_host['BRLAPI_LIBS'].split()) @@ -441,6 +506,8 @@ has_gettid = cc.has_function('gettid') # Create config-host.h config_host_data.set('CONFIG_LIBUDEV', libudev.found()) +config_host_data.set('CONFIG_MPATH', mpathpersist.found()) +config_host_data.set('CONFIG_MPATH_NEW_API', mpathpersist_new_api) config_host_data.set('CONFIG_SDL', sdl.found()) config_host_data.set('CONFIG_SDL_IMAGE', sdl_image.found()) config_host_data.set('CONFIG_VNC', vnc.found()) @@ -1205,7 +1272,7 @@ if have_tools executable('qemu-pr-helper', files('scsi/qemu-pr-helper.c', 'scsi/utils.c'), dependencies: [authz, crypto, io, qom, qemuutil, - libcap_ng, libudev, libmpathpersist], + libcap_ng, mpathpersist], install: true) endif @@ -1342,7 +1409,7 @@ summary_info += {'Audio drivers': config_host['CONFIG_AUDIO_DRIVERS']} summary_info += {'Block whitelist (rw)': config_host['CONFIG_BDRV_RW_WHITELIST']} summary_info += {'Block whitelist (ro)': config_host['CONFIG_BDRV_RO_WHITELIST']} summary_info += {'VirtFS support': config_host.has_key('CONFIG_VIRTFS')} -summary_info += {'Multipath support': config_host.has_key('CONFIG_MPATH')} +summary_info += {'Multipath support': mpathpersist.found()} summary_info += {'VNC support': vnc.found()} if vnc.found() summary_info += {'VNC SASL support': sasl.found()} diff --git a/meson_options.txt b/meson_options.txt index 543cf70043..b38a6ae92a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,6 +6,8 @@ option('docdir', type : 'string', value : 'doc', option('gettext', type : 'boolean', value : true, description: 'Localization of the GTK+ user interface') +option('mpath', type : 'feature', value : 'auto', + description: 'Multipath persistent reservation passthrough') option('sdl', type : 'feature', value : 'auto', description: 'SDL user interface') option('sdl_image', type : 'feature', value : 'auto', From 43b43a4027aefceff3bf7df86a109dd945ac6d49 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 17 Sep 2020 12:25:09 +0200 Subject: [PATCH 31/86] meson: extend libmpathpersist test for static linking libmultipath has a dependency on libdevmapper, so include it as well when static linking. It seems that the rabbit hole ends there. Signed-off-by: Paolo Bonzini --- meson.build | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index 8e9cd67235..5dd7728cc9 100644 --- a/meson.build +++ b/meson.build @@ -302,14 +302,25 @@ if targetos == 'linux' and have_tools and not get_option('mpath').disabled() mpath_lib_init(udev); return 0; }''' - libmultipath = cc.find_library('multipath', - required: get_option('mpath'), - static: enable_static) - libmpathpersist = cc.find_library('mpathpersist', - required: get_option('mpath'), - static: enable_static) - if libmultipath.found() and libmpathpersist.found() and libudev.found() - mpathlibs = [libmultipath, libmpathpersist, libudev] + mpathlibs = [libudev] + if enable_static + mpathlibs += cc.find_library('devmapper', + required: get_option('mpath'), + static: enable_static) + endif + mpathlibs += cc.find_library('multipath', + required: get_option('mpath'), + static: enable_static) + mpathlibs += cc.find_library('mpathpersist', + required: get_option('mpath'), + static: enable_static) + foreach lib: mpathlibs + if not lib.found() + mpathlibs = [] + break + endif + endforeach + if mpathlibs.length() > 0 if cc.links(mpath_test_source_new, dependencies: mpathlibs) mpathpersist = declare_dependency(dependencies: mpathlibs) mpathpersist_new_api = true From aa087962d7af6a2caa2caa0c449b76d01042c05a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 1 Sep 2020 11:15:30 -0400 Subject: [PATCH 32/86] configure: move malloc_trim/tcmalloc/jemalloc to meson Because LIBS is not used anymore, tcmalloc/jemalloc does not work with binaries whose description is in Meson. The fix is simply to move them to Meson too. For consistency with other configure options, specifying --enable-malloc-trim together with --enable-{tc,je}malloc becomes a fatal error. Reported-by: Stefan Hajnoczi Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- configure | 84 +++++------------------------------------------ meson.build | 28 +++++++++++++--- meson_options.txt | 5 +++ 3 files changed, 38 insertions(+), 79 deletions(-) diff --git a/configure b/configure index aade6eb285..cfbac88d9b 100755 --- a/configure +++ b/configure @@ -549,7 +549,7 @@ skip_meson=no gettext="" bogus_os="no" -malloc_trim="" +malloc_trim="auto" # parse CC options first for opt do @@ -1228,9 +1228,9 @@ for opt do ;; --enable-tcg) tcg="yes" ;; - --disable-malloc-trim) malloc_trim="no" + --disable-malloc-trim) malloc_trim="disabled" ;; - --enable-malloc-trim) malloc_trim="yes" + --enable-malloc-trim) malloc_trim="enabled" ;; --disable-spice) spice="no" ;; @@ -4384,77 +4384,14 @@ EOF fi fi +malloc=system if test "$tcmalloc" = "yes" && test "$jemalloc" = "yes" ; then echo "ERROR: tcmalloc && jemalloc can't be used at the same time" exit 1 -fi - -# Even if malloc_trim() is available, these non-libc memory allocators -# do not support it. -if test "$tcmalloc" = "yes" || test "$jemalloc" = "yes" ; then - if test "$malloc_trim" = "yes" ; then - echo "Disabling malloc_trim with non-libc memory allocator" - fi - malloc_trim="no" -fi - -####################################### -# malloc_trim - -if test "$malloc_trim" != "no" ; then - cat > $TMPC << EOF -#include -int main(void) { malloc_trim(0); return 0; } -EOF - if compile_prog "" "" ; then - malloc_trim="yes" - else - malloc_trim="no" - fi -fi - -########################################## -# tcmalloc probe - -if test "$tcmalloc" = "yes" ; then - cat > $TMPC << EOF -#include -int main(void) { - void *tmp = malloc(1); - if (tmp != NULL) { - return 0; - } - return 1; -} -EOF - - if compile_prog "" "-ltcmalloc" ; then - LIBS="-ltcmalloc $LIBS" - else - feature_not_found "tcmalloc" "install gperftools devel" - fi -fi - -########################################## -# jemalloc probe - -if test "$jemalloc" = "yes" ; then - cat > $TMPC << EOF -#include -int main(void) { - void *tmp = malloc(1); - if (tmp != NULL) { - return 0; - } - return 1; -} -EOF - - if compile_prog "" "-ljemalloc" ; then - LIBS="-ljemalloc $LIBS" - else - feature_not_found "jemalloc" "install jemalloc devel" - fi +elif test "$tcmalloc" = "yes" ; then + malloc=tcmalloc +elif test "$jemalloc" = "yes" ; then + malloc=jemalloc fi ########################################## @@ -6945,10 +6882,6 @@ if test "$gbm" = "yes" ; then fi -if test "$malloc_trim" = "yes" ; then - echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak -fi - if test "$avx2_opt" = "yes" ; then echo "CONFIG_AVX2_OPT=y" >> $config_host_mak fi @@ -7919,6 +7852,7 @@ NINJA=${ninja:-$PWD/ninjatool} $meson setup \ -Dstrip=$(if test "$strip_opt" = yes; then echo true; else echo false; fi) \ -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ + -Dmalloc=$malloc -Dmalloc_trim=$malloc_trim \ -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \ -Dvnc=$vnc -Dvnc_sasl=$vnc_sasl -Dvnc_jpeg=$vnc_jpeg -Dvnc_png=$vnc_png \ -Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f\ diff --git a/meson.build b/meson.build index 5dd7728cc9..afe53d8f0c 100644 --- a/meson.build +++ b/meson.build @@ -514,6 +514,26 @@ keyutils = dependency('libkeyutils', required: false, has_gettid = cc.has_function('gettid') +# Malloc tests + +malloc = [] +if get_option('malloc') == 'system' + has_malloc_trim = \ + not get_option('malloc_trim').disabled() and \ + cc.links('''#include + int main(void) { malloc_trim(0); return 0; }''') +else + has_malloc_trim = false + malloc = cc.find_library(get_option('malloc'), required: true) +endif +if not has_malloc_trim and get_option('malloc_trim').enabled() + if get_option('malloc') == 'system' + error('malloc_trim not available on this platform.') + else + error('malloc_trim not available with non-libc memory allocator') + endif +endif + # Create config-host.h config_host_data.set('CONFIG_LIBUDEV', libudev.found()) @@ -528,6 +548,7 @@ config_host_data.set('CONFIG_VNC_SASL', sasl.found()) config_host_data.set('CONFIG_XKBCOMMON', xkbcommon.found()) config_host_data.set('CONFIG_KEYUTILS', keyutils.found()) config_host_data.set('CONFIG_GETTID', has_gettid) +config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version())) config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0]) config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1]) @@ -911,7 +932,7 @@ util_ss.add_all(trace_ss) util_ss = util_ss.apply(config_all, strict: false) libqemuutil = static_library('qemuutil', sources: util_ss.sources() + stub_ss.sources() + genh, - dependencies: [util_ss.dependencies(), m, glib, socket]) + dependencies: [util_ss.dependencies(), m, glib, socket, malloc]) qemuutil = declare_dependency(link_with: libqemuutil, sources: genh + version_res) @@ -1450,7 +1471,7 @@ summary_info += {'Install blobs': config_host.has_key('INSTALL_BLOBS')} # summary_info += {'TCG debug enabled': config_host.has_key('CONFIG_DEBUG_TCG')} # summary_info += {'TCG interpreter': config_host.has_key('CONFIG_TCG_INTERPRETER')} #endif -summary_info += {'malloc trim support': config_host.has_key('CONFIG_MALLOC_TRIM')} +summary_info += {'malloc trim support': has_malloc_trim} summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')} summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')} summary_info += {'fdt support': config_host.has_key('CONFIG_FDT')} @@ -1512,8 +1533,7 @@ summary_info += {'lzfse support': config_host.has_key('CONFIG_LZFSE')} summary_info += {'zstd support': config_host.has_key('CONFIG_ZSTD')} summary_info += {'NUMA host support': config_host.has_key('CONFIG_NUMA')} summary_info += {'libxml2': config_host.has_key('CONFIG_LIBXML2')} -summary_info += {'tcmalloc support': config_host.has_key('CONFIG_TCMALLOC')} -summary_info += {'jemalloc support': config_host.has_key('CONFIG_JEMALLOC')} +summary_info += {'memory allocator': get_option('malloc')} summary_info += {'avx2 optimization': config_host.has_key('CONFIG_AVX2_OPT')} summary_info += {'avx512f optimization': config_host.has_key('CONFIG_AVX512F_OPT')} summary_info += {'replication support': config_host.has_key('CONFIG_REPLICATION')} diff --git a/meson_options.txt b/meson_options.txt index b38a6ae92a..8a59ec263d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,6 +6,11 @@ option('docdir', type : 'string', value : 'doc', option('gettext', type : 'boolean', value : true, description: 'Localization of the GTK+ user interface') +option('malloc_trim', type : 'feature', value : 'auto', + description: 'enable libc malloc_trim() for memory optimization') +option('malloc', type : 'combo', choices : ['system', 'tcmalloc', 'jemalloc'], + value: 'system', description: 'choose memory allocator to use') + option('mpath', type : 'feature', value : 'auto', description: 'Multipath persistent reservation passthrough') option('sdl', type : 'feature', value : 'auto', From 84ec0c24357250b53fd6034f0dfe5254f0e4458b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 4 Sep 2020 10:00:26 -0400 Subject: [PATCH 33/86] configure: fix --meson=/path/to/meson Due to a cut-and-paste error, the path to a user-specified meson was ignored and replaced by whatever was in the path. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index cfbac88d9b..1c05932a72 100755 --- a/configure +++ b/configure @@ -2015,7 +2015,7 @@ case "$meson" in fi meson="$python ${source_path}/meson/meson.py" ;; - *) meson=$(command -v meson) ;; + *) meson=$(command -v "$meson") ;; esac # Probe for ninja (used for compdb) From b4e312e953b71c8dbb9ff4ee195b6189a0bf628b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 1 Sep 2020 11:28:59 -0400 Subject: [PATCH 34/86] configure: move cocoa option to Meson While detection of the framework was already there, moving the option allows for better error reporting. Reported-by: Christophe de Dinechin Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- configure | 17 +++++++---------- meson.build | 9 +++++++-- meson_options.txt | 2 ++ ui/meson.build | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/configure b/configure index 1c05932a72..536ff9dc4b 100755 --- a/configure +++ b/configure @@ -457,7 +457,7 @@ bsd="no" linux="no" solaris="no" profiler="no" -cocoa="no" +cocoa="auto" softmmu="yes" linux_user="no" bsd_user="no" @@ -875,7 +875,7 @@ Darwin) QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS" QEMU_LDFLAGS="-arch x86_64 $QEMU_LDFLAGS" fi - cocoa="yes" + cocoa="enabled" audio_drv_list="coreaudio try-sdl" audio_possible_drivers="coreaudio sdl" QEMU_LDFLAGS="-framework CoreFoundation -framework IOKit $QEMU_LDFLAGS" @@ -1246,10 +1246,10 @@ for opt do ;; --enable-profiler) profiler="yes" ;; - --disable-cocoa) cocoa="no" + --disable-cocoa) cocoa="disabled" ;; --enable-cocoa) - cocoa="yes" ; + cocoa="enabled" ; audio_drv_list="coreaudio $(echo $audio_drv_list | sed s,coreaudio,,g)" ;; --disable-system) softmmu="no" @@ -2391,8 +2391,8 @@ fi # cocoa implies not SDL or GTK # (the cocoa UI code currently assumes it is always the active UI # and doesn't interact well with other UI frontend code) -if test "$cocoa" = "yes"; then - if test "$sdl" = "yes"; then +if test "$cocoa" = "enabled"; then + if test "$sdl" = "enabled"; then error_exit "Cocoa and SDL UIs cannot both be enabled at once" fi if test "$gtk" = "yes"; then @@ -6550,9 +6550,6 @@ if test "$have_x11" = "yes" && test "$need_x11" = "yes"; then echo "X11_CFLAGS=$x11_cflags" >> $config_host_mak echo "X11_LIBS=$x11_libs" >> $config_host_mak fi -if test "$cocoa" = "yes" ; then - echo "CONFIG_COCOA=y" >> $config_host_mak -fi if test "$iconv" = "yes" ; then echo "CONFIG_ICONV=y" >> $config_host_mak echo "ICONV_CFLAGS=$iconv_cflags" >> $config_host_mak @@ -7853,7 +7850,7 @@ NINJA=${ninja:-$PWD/ninjatool} $meson setup \ -Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \ -Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \ -Dmalloc=$malloc -Dmalloc_trim=$malloc_trim \ - -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \ + -Dcocoa=$cocoa -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \ -Dvnc=$vnc -Dvnc_sasl=$vnc_sasl -Dvnc_jpeg=$vnc_jpeg -Dvnc_png=$vnc_png \ -Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f\ $cross_arg \ diff --git a/meson.build b/meson.build index afe53d8f0c..34d4ff96aa 100644 --- a/meson.build +++ b/meson.build @@ -101,7 +101,7 @@ socket = [] version_res = [] coref = [] iokit = [] -cocoa = [] +cocoa = not_found hvf = [] if targetos == 'windows' socket = cc.find_library('ws2_32') @@ -114,7 +114,7 @@ if targetos == 'windows' elif targetos == 'darwin' coref = dependency('appleframeworks', modules: 'CoreFoundation') iokit = dependency('appleframeworks', modules: 'IOKit') - cocoa = dependency('appleframeworks', modules: 'Cocoa') + cocoa = dependency('appleframeworks', modules: 'Cocoa', required: get_option('cocoa')) hvf = dependency('appleframeworks', modules: 'Hypervisor') elif targetos == 'sunos' socket = [cc.find_library('socket'), @@ -126,6 +126,10 @@ elif targetos == 'haiku' cc.find_library('bsd')] endif +if not cocoa.found() and get_option('cocoa').enabled() + error('Cocoa not available on this platform') +endif + ################ # Dependencies # ################ @@ -536,6 +540,7 @@ endif # Create config-host.h +config_host_data.set('CONFIG_COCOA', cocoa.found()) config_host_data.set('CONFIG_LIBUDEV', libudev.found()) config_host_data.set('CONFIG_MPATH', mpathpersist.found()) config_host_data.set('CONFIG_MPATH_NEW_API', mpathpersist_new_api) diff --git a/meson_options.txt b/meson_options.txt index 8a59ec263d..46ea1d889a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -11,6 +11,8 @@ option('malloc_trim', type : 'feature', value : 'auto', option('malloc', type : 'combo', choices : ['system', 'tcmalloc', 'jemalloc'], value: 'system', description: 'choose memory allocator to use') +option('cocoa', type : 'feature', value : 'auto', + description: 'Cocoa user interface (macOS only)') option('mpath', type : 'feature', value : 'auto', description: 'Multipath persistent reservation passthrough') option('sdl', type : 'feature', value : 'auto', diff --git a/ui/meson.build b/ui/meson.build index dd6c110136..8a080c38e3 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -15,7 +15,7 @@ softmmu_ss.add(files( softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('input-linux.c')) softmmu_ss.add(when: 'CONFIG_SPICE', if_true: files('spice-core.c', 'spice-input.c', 'spice-display.c')) -softmmu_ss.add(when: [cocoa, 'CONFIG_COCOA'], if_true: files('cocoa.m')) +softmmu_ss.add(when: cocoa, if_true: files('cocoa.m')) vnc_ss = ss.source_set() vnc_ss.add(files( From 61f86416441a902f0244e4f26ca1a510b0273050 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 1 Sep 2020 11:34:18 -0400 Subject: [PATCH 35/86] configure: do not limit Hypervisor.framework test to Darwin Because the target/i386/hvf/meson.build rule culls hvf support on non-Darwin systems, a --enable-hvf build is succeeding. To fix this, just try the compilation test every time someone passes --enable-hvf. Reported-by: Christophe de Dinechin Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- configure | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 536ff9dc4b..803a97627b 100755 --- a/configure +++ b/configure @@ -870,7 +870,7 @@ Darwin) bsd="yes" darwin="yes" hax="yes" - hvf="yes" + hvf="" if [ "$cpu" = "x86_64" ] ; then QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS" QEMU_LDFLAGS="-arch x86_64 $QEMU_LDFLAGS" @@ -5823,16 +5823,18 @@ fi ################################################# # Check to see if we have the Hypervisor framework -if [ "$darwin" = "yes" ] ; then +if [ "$hvf" != "no" ] ; then cat > $TMPC << EOF #include int main() { return 0;} EOF if ! compile_object ""; then + if test "$hvf" = "yes"; then + error_exit "Hypervisor.framework not available" + fi hvf='no' else hvf='yes' - QEMU_LDFLAGS="-framework Hypervisor $QEMU_LDFLAGS" fi fi From fd5eef85fed024387d41adc4f7ca502c14ff62be Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 16 Sep 2020 05:00:53 -0400 Subject: [PATCH 36/86] meson: qtest: set "depends" correctly This does not have any effect on Meson's behavior itself, since "meson test" always rebuilds everything (that is one reason why we are not using it...). However, mtest2make can use this information to do a selective rebuild for the requested suite. Cc: Thomas Huth Signed-off-by: Paolo Bonzini --- meson.build | 7 ++++--- tests/qtest/meson.build | 8 +++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 34d4ff96aa..32f614b3dd 100644 --- a/meson.build +++ b/meson.build @@ -1103,7 +1103,7 @@ common_all = static_library('common', feature_to_c = find_program('scripts/feature_to_c.sh') -emulators = [] +emulators = {} foreach target : target_dirs config_target = config_target_mak[target] target_name = config_target['TARGET_NAME'] @@ -1222,7 +1222,8 @@ foreach target : target_dirs }] endif foreach exe: execs - emulators += executable(exe['name'], exe['sources'], + emulators += {exe['name']: + executable(exe['name'], exe['sources'], install: true, c_args: c_args, dependencies: arch_deps + deps + exe['dependencies'], @@ -1231,6 +1232,7 @@ foreach target : target_dirs link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []), link_args: link_args, gui_app: exe['gui']) + } if 'CONFIG_TRACE_SYSTEMTAP' in config_host foreach stp: [ @@ -1276,7 +1278,6 @@ if xkbcommon.found() dependencies: [qemuutil, xkbcommon], install: have_tools) endif -qemu_block_tools = [] if have_tools qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep], dependencies: [authz, block, crypto, io, qom, qemuutil], install: true) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 874b5be62b..4f7757ee93 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -228,10 +228,15 @@ foreach dir : target_dirs endif target_base = dir.split('-')[0] + qtest_emulator = emulators['qemu-system-' + target_base] qtests = get_variable('qtests_' + target_base, []) + qtests_generic + test_deps = [] qtest_env = environment() - qtest_env.set('QTEST_QEMU_IMG', './qemu-img') + if have_tools + qtest_env.set('QTEST_QEMU_IMG', './qemu-img') + test_deps += [qemu_img] + endif qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vmstate-daemon.sh') qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base) @@ -248,6 +253,7 @@ foreach dir : target_dirs # FIXME: missing dependency on the emulator binary and qemu-img test('qtest-@0@: @1@'.format(target_base, test), qtest_executables[test], + depends: [test_deps, qtest_emulator], env: qtest_env, args: ['--tap', '-k'], protocol: 'tap', From 48a81fd5b42e854e6c4b70cec60e023db9675e33 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 4 Sep 2020 10:06:06 -0400 Subject: [PATCH 37/86] mtest2make: add support for introspected test dependencies Right now all "make check" targets depend blindly on "all". If Meson is 0.56.0 or newer, we can use the correct dependencies using the new "depends" entry in "meson introspect --tests". Signed-off-by: Paolo Bonzini --- Makefile | 2 +- scripts/mtest2make.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 9af24f1e8c..54fc1a9d10 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,7 @@ ${ninja-targets-c_COMPILER} ${ninja-targets-cpp_COMPILER}: .var.command += -MP # reread (and MESON won't be empty anymore). ifneq ($(MESON),) Makefile.mtest: build.ninja scripts/mtest2make.py - $(MESON) introspect --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@ + $(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@ -include Makefile.mtest endif diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py index 9cbb2e374d..c3489a4605 100644 --- a/scripts/mtest2make.py +++ b/scripts/mtest2make.py @@ -5,6 +5,7 @@ # Author: Paolo Bonzini from collections import defaultdict +import itertools import json import os import shlex @@ -36,7 +37,7 @@ SPEED = quick introspect = json.load(sys.stdin) i = 0 -def process_tests(test, suites): +def process_tests(test, targets, suites): global i env = ' '.join(('%s=%s' % (shlex.quote(k), shlex.quote(v)) for k, v in test['env'].items())) @@ -58,12 +59,19 @@ def process_tests(test, suites): i += 1 if test['workdir'] is not None: print('.test.dir.%d := %s' % (i, shlex.quote(test['workdir']))) + + if 'depends' in test: + deps = (targets.get(x, []) for x in test['depends']) + deps = itertools.chain.from_iterable(deps) + else: + deps = ['all'] + print('.test.name.%d := %s' % (i, test['name'])) print('.test.driver.%d := %s' % (i, driver)) print('.test.env.%d := $(.test.env) %s' % (i, env)) print('.test.cmd.%d := %s' % (i, cmd)) print('.PHONY: run-test-%d' % (i,)) - print('run-test-%d: all' % (i,)) + print('run-test-%d: %s' % (i, ' '.join(deps))) print('\t@$(call .test.run,%d,$(.test.output-format))' % (i,)) test_suites = test['suite'] or ['default'] @@ -102,16 +110,19 @@ def emit_suite(name, suite, prefix): print('.tests += $(.test.$(SPEED).%s)' % (target, )) print('endif') +targets = {t['id']: [os.path.relpath(f) for f in t['filename']] + for t in introspect['targets']} + testsuites = defaultdict(Suite) for test in introspect['tests']: - process_tests(test, testsuites) + process_tests(test, targets, testsuites) emit_prolog(testsuites, 'check') for name, suite in testsuites.items(): emit_suite(name, suite, 'check') benchsuites = defaultdict(Suite) for test in introspect['benchmarks']: - process_tests(test, benchsuites) + process_tests(test, targets, benchsuites) emit_prolog(benchsuites, 'bench') for name, suite in benchsuites.items(): emit_suite(name, suite, 'bench') From 05512f55aaca92505b75d8fa6818b088a5eeb07f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 16 Sep 2020 15:31:11 -0400 Subject: [PATCH 38/86] meson: report accelerator support Note that the "real" support is reported. A configuration like --disable-system --enable-kvm will report "no" for "KVM support" because no KVM-supported target is being compiled. Reported-by: Andrew Jones Signed-off-by: Paolo Bonzini --- meson.build | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 32f614b3dd..f4a3815696 100644 --- a/meson.build +++ b/meson.build @@ -583,6 +583,7 @@ endforeach genh += configure_file(output: 'config-host.h', configuration: config_host_data) minikconf = find_program('scripts/minikconf.py') +config_all = {} config_all_devices = {} config_all_disas = {} config_devices_mak_list = [] @@ -639,6 +640,14 @@ kconfig_external_symbols = [ ] ignored = ['TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_DIRS'] +accel_symbols = [ + 'CONFIG_KVM', + 'CONFIG_HAX', + 'CONFIG_HVF', + 'CONFIG_TCG', + 'CONFIG_WHPX' +] + foreach target : target_dirs config_target = keyval.load(meson.current_build_dir() / target / 'config-target.mak') @@ -667,6 +676,11 @@ foreach target : target_dirs config_target_data.set(k, v) endif endforeach + foreach sym: accel_symbols + if config_target.has_key(sym) + config_all += { sym: 'y' } + endif + endforeach config_target_h += {target: configure_file(output: target + '-config-target.h', configuration: config_target_data)} @@ -711,7 +725,7 @@ endforeach # targets that are not built for this compilation. The CONFIG_ALL # pseudo symbol replaces it. -config_all = config_all_devices +config_all += config_all_devices config_all += config_host config_all += config_all_disas config_all += { @@ -1467,16 +1481,15 @@ summary_info += {'Linux AIO support': config_host.has_key('CONFIG_LINUX_AIO')} summary_info += {'Linux io_uring support': config_host.has_key('CONFIG_LINUX_IO_URING')} summary_info += {'ATTR/XATTR support': config_host.has_key('CONFIG_ATTR')} summary_info += {'Install blobs': config_host.has_key('INSTALL_BLOBS')} -# TODO: add back KVM/HAX/HVF/WHPX/TCG -#summary_info += {'KVM support': have_kvm'} -#summary_info += {'HAX support': have_hax'} -#summary_info += {'HVF support': have_hvf'} -#summary_info += {'WHPX support': have_whpx'} -#summary_info += {'TCG support': have_tcg'} -#if get_option('tcg') -# summary_info += {'TCG debug enabled': config_host.has_key('CONFIG_DEBUG_TCG')} -# summary_info += {'TCG interpreter': config_host.has_key('CONFIG_TCG_INTERPRETER')} -#endif +summary_info += {'KVM support': config_all.has_key('CONFIG_KVM')} +summary_info += {'HAX support': config_all.has_key('CONFIG_HAX')} +summary_info += {'HVF support': config_all.has_key('CONFIG_HVF')} +summary_info += {'WHPX support': config_all.has_key('CONFIG_WHPX')} +summary_info += {'TCG support': config_all.has_key('CONFIG_TCG')} +if config_all.has_key('CONFIG_TCG') + summary_info += {'TCG debug enabled': config_host.has_key('CONFIG_DEBUG_TCG')} + summary_info += {'TCG interpreter': config_host.has_key('CONFIG_TCG_INTERPRETER')} +endif summary_info += {'malloc trim support': has_malloc_trim} summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')} summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')} From a4c13869f95cb45d657cc1df3803f633221d4971 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 12:11:02 +0200 Subject: [PATCH 39/86] oslib: do not call g_strdup from qemu_get_exec_dir Just return the directory without requiring the caller to free it. This also removes a bogus check for NULL in os_find_datadir and module_load_one; g_strdup of a static variable cannot return NULL. Signed-off-by: Paolo Bonzini --- include/qemu/osdep.h | 8 ++------ os-posix.c | 6 +----- os-win32.c | 2 +- tests/qtest/fuzz/fuzz.c | 4 ++-- util/module.c | 7 +------ util/oslib-posix.c | 8 +++++--- util/oslib-win32.c | 12 ++++++++---- 7 files changed, 20 insertions(+), 27 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index dad44be043..f9ec8c84e9 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -597,12 +597,8 @@ char *qemu_get_local_state_pathname(const char *relative_pathname); * Try OS specific API first, if not working, parse from argv0. */ void qemu_init_exec_dir(const char *argv0); -/* Get the saved exec dir. - * - * The caller is responsible for releasing the value returned with g_free() - * after use. - */ -char *qemu_get_exec_dir(void); +/* Get the saved exec dir. */ +const char *qemu_get_exec_dir(void); /** * qemu_getauxval: diff --git a/os-posix.c b/os-posix.c index 0bfd8e2d3c..36e344c544 100644 --- a/os-posix.c +++ b/os-posix.c @@ -90,13 +90,9 @@ void os_setup_signal_handling(void) */ char *os_find_datadir(void) { - g_autofree char *exec_dir = NULL; g_autofree char *dir = NULL; - exec_dir = qemu_get_exec_dir(); - g_return_val_if_fail(exec_dir != NULL, NULL); - - dir = g_build_filename(exec_dir, "pc-bios", NULL); + dir = g_build_filename(qemu_get_exec_dir(), "pc-bios", NULL); if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { return g_steal_pointer(&dir); } diff --git a/os-win32.c b/os-win32.c index c9c3afe648..eb8501b9e5 100644 --- a/os-win32.c +++ b/os-win32.c @@ -65,7 +65,7 @@ void os_setup_early_signal_handling(void) */ char *os_find_datadir(void) { - return qemu_get_exec_dir(); + return g_strdup(qemu_get_exec_dir()); } void os_set_line_buffering(void) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 7f266ffc63..d3a3ccdec9 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -143,7 +143,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) { char *target_name; - char *bindir, *datadir; + const char *bindir; + char *datadir; bool serialize = false; /* Initialize qgraph and modules */ @@ -166,7 +167,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) */ bindir = g_path_get_dirname(**argv); datadir = g_build_filename(bindir, "pc-bios", NULL); - g_free(bindir); if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) { qemu_add_data_dir(datadir); } diff --git a/util/module.c b/util/module.c index 34772e7d87..9ffe83bb32 100644 --- a/util/module.c +++ b/util/module.c @@ -172,7 +172,6 @@ bool module_load_one(const char *prefix, const char *lib_name) #ifdef CONFIG_MODULES char *fname = NULL; - char *exec_dir; #ifdef CONFIG_MODULE_UPGRADES char *version_dir; #endif @@ -199,13 +198,12 @@ bool module_load_one(const char *prefix, const char *lib_name) return true; } - exec_dir = qemu_get_exec_dir(); search_dir = getenv("QEMU_MODULE_DIR"); if (search_dir != NULL) { dirs[n_dirs++] = g_strdup_printf("%s", search_dir); } dirs[n_dirs++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR); - dirs[n_dirs++] = g_strdup_printf("%s", exec_dir ? : ""); + dirs[n_dirs++] = g_strdup(qemu_get_exec_dir()); #ifdef CONFIG_MODULE_UPGRADES version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION), @@ -216,9 +214,6 @@ bool module_load_one(const char *prefix, const char *lib_name) assert(n_dirs <= ARRAY_SIZE(dirs)); - g_free(exec_dir); - exec_dir = NULL; - for (i = 0; i < n_dirs; i++) { fname = g_strdup_printf("%s/%s%s", dirs[i], module_name, CONFIG_HOST_DSOSUF); diff --git a/util/oslib-posix.c b/util/oslib-posix.c index f5f676f079..18531fc859 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -366,7 +366,9 @@ void qemu_init_exec_dir(const char *argv0) char *p = NULL; char buf[PATH_MAX]; - assert(!exec_dir[0]); + if (exec_dir[0]) { + return; + } #if defined(__linux__) { @@ -439,9 +441,9 @@ void qemu_init_exec_dir(const char *argv0) g_free(dir); } -char *qemu_get_exec_dir(void) +const char *qemu_get_exec_dir(void) { - return g_strdup(exec_dir); + return exec_dir; } static void sigbus_handler(int signal) diff --git a/util/oslib-win32.c b/util/oslib-win32.c index c654dafd93..1a33912944 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -315,7 +315,7 @@ void qemu_set_tty_echo(int fd, bool echo) } } -static char exec_dir[PATH_MAX]; +static char *exec_dir; void qemu_init_exec_dir(const char *argv0) { @@ -324,6 +324,10 @@ void qemu_init_exec_dir(const char *argv0) char buf[MAX_PATH]; DWORD len; + if (exec_dir) { + return; + } + len = GetModuleFileName(NULL, buf, sizeof(buf) - 1); if (len == 0) { return; @@ -336,13 +340,13 @@ void qemu_init_exec_dir(const char *argv0) } *p = 0; if (access(buf, R_OK) == 0) { - pstrcpy(exec_dir, sizeof(exec_dir), buf); + exec_dir = g_strdup(buf); } } -char *qemu_get_exec_dir(void) +const char *qemu_get_exec_dir(void) { - return g_strdup(exec_dir); + return exec_dir; } #if !GLIB_CHECK_VERSION(2, 50, 0) From ec986777accd688c1b7159778c9cc729e54a87f4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 31 Aug 2020 07:58:10 -0400 Subject: [PATCH 40/86] fuzz: use qemu_get_exec_dir Make things consistent with how softmmu/vl.c uses os_find_datadir. Initializing the path to the executables will also be needed for get_relocatable_path to work. Reviewed-by: Thomas Huth Reviewed-by: Alexander Bulekov Signed-off-by: Paolo Bonzini --- tests/qtest/fuzz/fuzz.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index d3a3ccdec9..c4dc5fa629 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -153,6 +153,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) module_call_init(MODULE_INIT_QOM); module_call_init(MODULE_INIT_LIBQOS); + qemu_init_exec_dir(**argv); target_name = strstr(**argv, "-target-"); if (target_name) { /* The binary name specifies the target */ target_name += strlen("-target-"); @@ -165,7 +166,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) * location of the executable. Using this we add exec_dir/pc-bios to * the datadirs. */ - bindir = g_path_get_dirname(**argv); + bindir = qemu_get_exec_dir(); datadir = g_build_filename(bindir, "pc-bios", NULL); if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) { qemu_add_data_dir(datadir); From 9386a4a7150fe11690af1897cf28c206c54cde9c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 12:00:59 +0200 Subject: [PATCH 41/86] oslib-posix: default exec_dir to bindir If the exec_dir cannot be retrieved, just assume it's the installation directory that was specified at configure time. This makes it simpler to reason about what the callers will do if they get back an empty path. Signed-off-by: Paolo Bonzini --- meson.build | 2 +- util/oslib-posix.c | 23 ++++++++--------------- util/oslib-win32.c | 4 +++- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/meson.build b/meson.build index f4a3815696..fbef2e11e9 100644 --- a/meson.build +++ b/meson.build @@ -560,7 +560,7 @@ config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1] config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2]) arrays = ['CONFIG_AUDIO_DRIVERS', 'CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST'] -strings = ['HOST_DSOSUF', 'CONFIG_IASL', 'qemu_confdir', 'qemu_datadir', +strings = ['HOST_DSOSUF', 'CONFIG_IASL', 'bindir', 'qemu_confdir', 'qemu_datadir', 'qemu_moddir', 'qemu_localstatedir', 'qemu_helperdir', 'qemu_localedir', 'qemu_icondir', 'qemu_desktopdir', 'qemu_firmwarepath'] foreach k, v: config_host diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 18531fc859..1739930e65 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -358,15 +358,14 @@ void qemu_set_tty_echo(int fd, bool echo) tcsetattr(fd, TCSANOW, &tty); } -static char exec_dir[PATH_MAX]; +static const char *exec_dir; void qemu_init_exec_dir(const char *argv0) { - char *dir; char *p = NULL; char buf[PATH_MAX]; - if (exec_dir[0]) { + if (exec_dir) { return; } @@ -425,20 +424,14 @@ void qemu_init_exec_dir(const char *argv0) #endif /* If we don't have any way of figuring out the actual executable location then try argv[0]. */ - if (!p) { - if (!argv0) { - return; - } + if (!p && argv0) { p = realpath(argv0, buf); - if (!p) { - return; - } } - dir = g_path_get_dirname(p); - - pstrcpy(exec_dir, sizeof(exec_dir), dir); - - g_free(dir); + if (p) { + exec_dir = g_path_get_dirname(p); + } else { + exec_dir = CONFIG_BINDIR; + } } const char *qemu_get_exec_dir(void) diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 1a33912944..051afb217b 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -315,7 +315,7 @@ void qemu_set_tty_echo(int fd, bool echo) } } -static char *exec_dir; +static const char *exec_dir; void qemu_init_exec_dir(const char *argv0) { @@ -341,6 +341,8 @@ void qemu_init_exec_dir(const char *argv0) *p = 0; if (access(buf, R_OK) == 0) { exec_dir = g_strdup(buf); + } else { + exec_dir = CONFIG_BINDIR; } } From f4f5ed2cbde65acaa1bd88d00cc23fa8bf6b5ed9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 11:55:47 +0200 Subject: [PATCH 42/86] cutils: introduce get_relocated_path Add the function that will compute a relocated version of the directories in CONFIG_QEMU_*DIR and CONFIG_QEMU_*PATH. Signed-off-by: Paolo Bonzini --- include/qemu/cutils.h | 12 +++++++++ meson.build | 4 +-- util/cutils.c | 61 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index eb59852dfd..3a86ec0321 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -184,4 +184,16 @@ int uleb128_decode_small(const uint8_t *in, uint32_t *n); */ int qemu_pstrcmp0(const char **str1, const char **str2); + +/** + * get_relocated_path: + * @dir: the directory (typically a `CONFIG_*DIR` variable) to be relocated. + * + * Returns a path for @dir that uses the directory of the running executable + * as the prefix. For example, if `bindir` is `/usr/bin` and @dir is + * `/usr/share/qemu`, the function will append `../share/qemu` to the + * directory that contains the running executable and return the result. + */ +char *get_relocated_path(const char *dir); + #endif diff --git a/meson.build b/meson.build index fbef2e11e9..b3133cf39d 100644 --- a/meson.build +++ b/meson.build @@ -560,9 +560,9 @@ config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1] config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2]) arrays = ['CONFIG_AUDIO_DRIVERS', 'CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST'] -strings = ['HOST_DSOSUF', 'CONFIG_IASL', 'bindir', 'qemu_confdir', 'qemu_datadir', +strings = ['HOST_DSOSUF', 'CONFIG_IASL', 'bindir', 'prefix', 'qemu_confdir', 'qemu_datadir', 'qemu_moddir', 'qemu_localstatedir', 'qemu_helperdir', 'qemu_localedir', - 'qemu_icondir', 'qemu_desktopdir', 'qemu_firmwarepath'] + 'qemu_icondir', 'qemu_desktopdir', 'qemu_firmwarepath', 'sysconfdir'] foreach k, v: config_host if arrays.contains(k) if v != '' diff --git a/util/cutils.c b/util/cutils.c index 36ce712271..8da34e04b0 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -889,3 +889,64 @@ int qemu_pstrcmp0(const char **str1, const char **str2) { return g_strcmp0(*str1, *str2); } + +static inline bool starts_with_prefix(const char *dir) +{ + size_t prefix_len = strlen(CONFIG_PREFIX); + return !memcmp(dir, CONFIG_PREFIX, prefix_len) && + (!dir[prefix_len] || G_IS_DIR_SEPARATOR(dir[prefix_len])); +} + +/* Return the next path component in dir, and store its length in *p_len. */ +static inline const char *next_component(const char *dir, int *p_len) +{ + int len; + while (*dir && G_IS_DIR_SEPARATOR(*dir)) { + dir++; + } + len = 0; + while (dir[len] && !G_IS_DIR_SEPARATOR(dir[len])) { + len++; + } + *p_len = len; + return dir; +} + +char *get_relocated_path(const char *dir) +{ + size_t prefix_len = strlen(CONFIG_PREFIX); + const char *bindir = CONFIG_BINDIR; + const char *exec_dir = qemu_get_exec_dir(); + GString *result; + int len_dir, len_bindir; + + /* Fail if qemu_init_exec_dir was not called. */ + assert(exec_dir[0]); + if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) { + return strdup(dir); + } + + result = g_string_new(exec_dir); + + /* Advance over common components. */ + len_dir = len_bindir = prefix_len; + do { + dir += len_dir; + bindir += len_bindir; + dir = next_component(dir, &len_dir); + bindir = next_component(bindir, &len_bindir); + } while (len_dir == len_bindir && !memcmp(dir, bindir, len_dir)); + + /* Ascend from bindir to the common prefix with dir. */ + while (len_bindir) { + bindir += len_bindir; + g_string_append(result, "/.."); + bindir = next_component(bindir, &len_bindir); + } + + if (*dir) { + assert(G_IS_DIR_SEPARATOR(dir[-1])); + g_string_append(result, dir - 1); + } + return result->str; +} From fcb4f59c8794f0dea9f9b9d988a016ead5df9353 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 12:00:41 +0200 Subject: [PATCH 43/86] oslib-posix: relocate path to /var MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- util/oslib-posix.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 1739930e65..f15234b5c0 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -339,8 +339,10 @@ int qemu_pipe(int pipefd[2]) char * qemu_get_local_state_pathname(const char *relative_pathname) { - return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR, - relative_pathname); + g_autofree char *dir = g_strdup_printf("%s/%s", + CONFIG_QEMU_LOCALSTATEDIR, + relative_pathname); + return get_relocated_path(dir); } void qemu_set_tty_echo(int fd, bool echo) From 1b934064817e3bc7c7e6b4a4af57b9ab685093e2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 12:00:18 +0200 Subject: [PATCH 44/86] module: relocate path to modules Signed-off-by: Paolo Bonzini --- util/module.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/module.c b/util/module.c index 9ffe83bb32..a44ec38d93 100644 --- a/util/module.c +++ b/util/module.c @@ -19,6 +19,7 @@ #endif #include "qemu/queue.h" #include "qemu/module.h" +#include "qemu/cutils.h" #ifdef CONFIG_MODULE_UPGRADES #include "qemu-version.h" #endif @@ -202,7 +203,7 @@ bool module_load_one(const char *prefix, const char *lib_name) if (search_dir != NULL) { dirs[n_dirs++] = g_strdup_printf("%s", search_dir); } - dirs[n_dirs++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR); + dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR); dirs[n_dirs++] = g_strdup(qemu_get_exec_dir()); #ifdef CONFIG_MODULE_UPGRADES From 63c4db4c2e6d221cecb5aafa365934bb05724cb4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 11:56:16 +0200 Subject: [PATCH 45/86] net: relocate paths to helpers and scripts Signed-off-by: Paolo Bonzini --- include/net/net.h | 4 ++-- net/tap.c | 26 +++++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/net/net.h b/include/net/net.h index e7ef42d62b..897b2d7595 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -209,8 +209,8 @@ void netdev_add(QemuOpts *opts, Error **errp); int net_hub_id_for_client(NetClientState *nc, int *id); NetClientState *net_hub_port_find(int hub_id); -#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" -#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" +#define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifup" +#define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifdown" #define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper" #define DEFAULT_BRIDGE_INTERFACE "br0" diff --git a/net/tap.c b/net/tap.c index 14dc904fca..04ce72dd2f 100644 --- a/net/tap.c +++ b/net/tap.c @@ -478,6 +478,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge, Error **errp) { sigset_t oldmask, mask; + g_autofree char *default_helper = NULL; int pid, status; char *args[5]; char **parg; @@ -487,6 +488,10 @@ static int net_bridge_run_helper(const char *helper, const char *bridge, sigaddset(&mask, SIGCHLD); sigprocmask(SIG_BLOCK, &mask, &oldmask); + if (!helper) { + helper = default_helper = get_relocated_path(DEFAULT_BRIDGE_HELPER); + } + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { error_setg_errno(errp, errno, "socketpair() failed"); return -1; @@ -588,8 +593,7 @@ int net_init_bridge(const Netdev *netdev, const char *name, assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE); bridge = &netdev->u.bridge; - - helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER; + helper = bridge->has_helper ? bridge->helper : NULL; br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE; fd = net_bridge_run_helper(helper, br, errp); @@ -773,8 +777,8 @@ int net_init_tap(const Netdev *netdev, const char *name, const NetdevTapOptions *tap; int fd, vnet_hdr = 0, i = 0, queues; /* for the no-fd, no-helper case */ - const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */ - const char *downscript = NULL; + const char *script; + const char *downscript; Error *err = NULL; const char *vhostfdname; char ifname[128]; @@ -784,6 +788,8 @@ int net_init_tap(const Netdev *netdev, const char *name, tap = &netdev->u.tap; queues = tap->has_queues ? tap->queues : 1; vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL; + script = tap->has_script ? tap->script : NULL; + downscript = tap->has_downscript ? tap->downscript : NULL; /* QEMU hubs do not support multiqueue tap, in this case peer is set. * For -netdev, peer is always NULL. */ @@ -934,13 +940,19 @@ free_fail: return -1; } } else { + g_autofree char *default_script = NULL; + g_autofree char *default_downscript = NULL; if (tap->has_vhostfds) { error_setg(errp, "vhostfds= is invalid if fds= wasn't specified"); return -1; } - script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT; - downscript = tap->has_downscript ? tap->downscript : - DEFAULT_NETWORK_DOWN_SCRIPT; + + if (!script) { + script = default_script = get_relocated_path(DEFAULT_NETWORK_SCRIPT); + } + if (!downscript) { + downscript = default_downscript = get_relocated_path(DEFAULT_NETWORK_SCRIPT); + } if (tap->has_ifname) { pstrcpy(ifname, sizeof ifname, tap->ifname); From ea1edcd7da1a375ef7ccf8aa93b72827b518ad8e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 11:57:56 +0200 Subject: [PATCH 46/86] vl: relocate paths to data directories As an additional advantage, the logic is now unified between POSIX and Win32 systems. Signed-off-by: Paolo Bonzini --- include/qemu-common.h | 1 - include/sysemu/sysemu.h | 2 +- os-posix.c | 20 -------------------- os-win32.c | 11 ----------- softmmu/vl.c | 40 ++++++++++++++++++++++++++++------------ tests/qtest/fuzz/fuzz.c | 5 +++-- 6 files changed, 32 insertions(+), 47 deletions(-) diff --git a/include/qemu-common.h b/include/qemu-common.h index cc902b690d..fda7dc6ca7 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -131,7 +131,6 @@ char *qemu_find_file(int type, const char *name); /* OS specific functions */ void os_setup_early_signal_handling(void); -char *os_find_datadir(void); int os_parse_cmd_args(int index, const char *optarg); /* diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 4b6a5c459c..817ff4cf75 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -14,7 +14,7 @@ extern const char *qemu_name; extern QemuUUID qemu_uuid; extern bool qemu_uuid_set; -void qemu_add_data_dir(const char *path); +void qemu_add_data_dir(char *path); void qemu_add_exit_notifier(Notifier *notify); void qemu_remove_exit_notifier(Notifier *notify); diff --git a/os-posix.c b/os-posix.c index 36e344c544..1de2839554 100644 --- a/os-posix.c +++ b/os-posix.c @@ -80,26 +80,6 @@ void os_setup_signal_handling(void) sigaction(SIGTERM, &act, NULL); } -/* - * Find a likely location for support files using the location of the binary. - * When running from the build tree this will be "$bindir/pc-bios". - * Otherwise, this is CONFIG_QEMU_DATADIR. - * - * The caller must use g_free() to free the returned data when it is - * no longer required. - */ -char *os_find_datadir(void) -{ - g_autofree char *dir = NULL; - - dir = g_build_filename(qemu_get_exec_dir(), "pc-bios", NULL); - if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { - return g_steal_pointer(&dir); - } - - return g_strdup(CONFIG_QEMU_DATADIR); -} - void os_set_proc_name(const char *s) { #if defined(PR_SET_NAME) diff --git a/os-win32.c b/os-win32.c index eb8501b9e5..fd1137bab1 100644 --- a/os-win32.c +++ b/os-win32.c @@ -57,17 +57,6 @@ void os_setup_early_signal_handling(void) atexit(os_undo_timer_resolution); } -/* - * Look for support files in the same directory as the executable. - * - * The caller must use g_free() to free the returned data when it is - * no longer required. - */ -char *os_find_datadir(void) -{ - return g_strdup(qemu_get_exec_dir()); -} - void os_set_line_buffering(void) { setbuf(stdout, NULL); diff --git a/softmmu/vl.c b/softmmu/vl.c index 50d8c2e42e..12e8ca22bd 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2005,7 +2005,7 @@ char *qemu_find_file(int type, const char *name) return NULL; } -void qemu_add_data_dir(const char *path) +void qemu_add_data_dir(char *path) { int i; @@ -2017,10 +2017,11 @@ void qemu_add_data_dir(const char *path) } for (i = 0; i < data_dir_idx; i++) { if (strcmp(data_dir[i], path) == 0) { - return; /* duplicate */ + g_free(path); /* duplicate */ + return; } } - data_dir[data_dir_idx++] = g_strdup(path); + data_dir[data_dir_idx++] = path; } static inline bool nonempty_str(const char *str) @@ -2829,6 +2830,26 @@ static void create_default_memdev(MachineState *ms, const char *path) &error_fatal); } +/* + * Find a likely location for support files using the location of the binary. + * When running from the build tree this will be "$bindir/pc-bios". + * Otherwise, this is CONFIG_QEMU_DATADIR (possibly relocated). + * + * The caller must use g_free() to free the returned data when it is + * no longer required. + */ +static char *find_datadir(void) +{ + g_autofree char *dir = NULL; + + dir = g_build_filename(qemu_get_exec_dir(), "pc-bios", NULL); + if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { + return g_steal_pointer(&dir); + } + + return get_relocated_path(CONFIG_QEMU_DATADIR); +} + void qemu_init(int argc, char **argv, char **envp) { int i; @@ -2862,7 +2883,7 @@ void qemu_init(int argc, char **argv, char **envp) Error *main_loop_err = NULL; Error *err = NULL; bool list_data_dirs = false; - char *dir, **dirs; + char **dirs; const char *mem_path = NULL; bool have_custom_ram_size; BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); @@ -3195,7 +3216,7 @@ void qemu_init(int argc, char **argv, char **envp) if (is_help_option(optarg)) { list_data_dirs = true; } else { - qemu_add_data_dir(optarg); + qemu_add_data_dir(g_strdup(optarg)); } break; case QEMU_OPTION_bios: @@ -3927,17 +3948,12 @@ void qemu_init(int argc, char **argv, char **envp) /* add configured firmware directories */ dirs = g_strsplit(CONFIG_QEMU_FIRMWAREPATH, G_SEARCHPATH_SEPARATOR_S, 0); for (i = 0; dirs[i] != NULL; i++) { - qemu_add_data_dir(dirs[i]); + qemu_add_data_dir(get_relocated_path(dirs[i])); } g_strfreev(dirs); /* try to find datadir relative to the executable path */ - dir = os_find_datadir(); - qemu_add_data_dir(dir); - g_free(dir); - - /* add the datadir specified when building */ - qemu_add_data_dir(CONFIG_QEMU_DATADIR); + qemu_add_data_dir(find_datadir()); /* -L help lists the data directories and exits. */ if (list_data_dirs) { diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index c4dc5fa629..d926c490c5 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -170,8 +170,9 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) datadir = g_build_filename(bindir, "pc-bios", NULL); if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) { qemu_add_data_dir(datadir); - } - g_free(datadir); + } else { + g_free(datadir); + } } else if (*argc > 1) { /* The target is specified as an argument */ target_name = (*argv)[1]; if (!strstr(target_name, "--fuzz-target=")) { From 580e6ad6a4ebc1a039c86b7b7f0f2dcff0019091 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 11:59:50 +0200 Subject: [PATCH 47/86] vl: relocate path to configuration file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- softmmu/vl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/softmmu/vl.c b/softmmu/vl.c index 12e8ca22bd..22bc570df4 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2676,8 +2676,9 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp) static int qemu_read_default_config_file(void) { int ret; + g_autofree char *file = get_relocated_path(CONFIG_QEMU_CONFDIR "/qemu.conf"); - ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR "/qemu.conf"); + ret = qemu_read_config_file(file); if (ret < 0 && ret != -ENOENT) { return ret; } From f761b41a62c8ac12f26727dddc7ae1dd3ca9802b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 11:58:34 +0200 Subject: [PATCH 48/86] qemu-bridge-helper: relocate path to default ACL Signed-off-by: Paolo Bonzini --- qemu-bridge-helper.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c index 88b26747fc..a26e1663f0 100644 --- a/qemu-bridge-helper.c +++ b/qemu-bridge-helper.c @@ -40,6 +40,7 @@ #endif #include "qemu/queue.h" +#include "qemu/cutils.h" #include "net/tap-linux.h" @@ -245,6 +246,7 @@ int main(int argc, char **argv) ACLList acl_list; int access_allowed, access_denied; int ret = EXIT_SUCCESS; + g_autofree char *acl_file = NULL; #ifdef CONFIG_LIBCAP_NG /* if we're run from an suid binary, immediately drop privileges preserving @@ -257,6 +259,8 @@ int main(int argc, char **argv) } #endif + qemu_init_exec_dir(argv[0]); + /* parse arguments */ for (index = 1; index < argc; index++) { if (strcmp(argv[index], "--use-vnet") == 0) { @@ -282,9 +286,10 @@ int main(int argc, char **argv) /* parse default acl file */ QSIMPLEQ_INIT(&acl_list); - if (parse_acl_file(DEFAULT_ACL_FILE, &acl_list) == -1) { + acl_file = get_relocated_path(DEFAULT_ACL_FILE); + if (parse_acl_file(acl_file, &acl_list) == -1) { fprintf(stderr, "failed to parse default acl file `%s'\n", - DEFAULT_ACL_FILE); + acl_file); ret = EXIT_FAILURE; goto cleanup; } From a9eacf8b4dd1d13f89fb735236e32dcfafef3e93 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 11:59:00 +0200 Subject: [PATCH 49/86] qga: relocate path to default configuration and hook Signed-off-by: Paolo Bonzini --- qga/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/qga/main.c b/qga/main.c index 3febf3b0fd..740f5f7303 100644 --- a/qga/main.c +++ b/qga/main.c @@ -29,6 +29,7 @@ #include "qapi/error.h" #include "channel.h" #include "qemu/bswap.h" +#include "qemu/cutils.h" #include "qemu/help_option.h" #include "qemu/sockets.h" #include "qemu/systemd.h" @@ -968,7 +969,7 @@ static void config_load(GAConfig *config) { GError *gerr = NULL; GKeyFile *keyfile; - const char *conf = g_getenv("QGA_CONF") ?: QGA_CONF_DEFAULT; + g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT); /* read system config */ keyfile = g_key_file_new(); @@ -1027,7 +1028,7 @@ end: if (gerr && !(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT)) { g_critical("error loading configuration from path: %s, %s", - QGA_CONF_DEFAULT, gerr->message); + conf, gerr->message); exit(EXIT_FAILURE); } g_clear_error(&gerr); @@ -1141,7 +1142,7 @@ static void config_parse(GAConfig *config, int argc, char **argv) #ifdef CONFIG_FSFREEZE case 'F': g_free(config->fsfreeze_hook); - config->fsfreeze_hook = g_strdup(optarg ?: QGA_FSFREEZE_HOOK_DEFAULT); + config->fsfreeze_hook = optarg ? g_strdup(optarg) : get_relocated_path(QGA_FSFREEZE_HOOK_DEFAULT); break; #endif case 't': @@ -1463,6 +1464,7 @@ int main(int argc, char **argv) config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; + qemu_init_exec_dir(argv[0]); qga_qmp_init_marshal(&ga_commands); init_dfl_pathnames(); From 77d910fb6aaea60381e487073845ad2152a9e1f6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 11:59:27 +0200 Subject: [PATCH 50/86] ui: relocate paths to icons and translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- ui/gtk.c | 10 ++++++++-- ui/sdl2.c | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 1c59de2af4..b11594d817 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -51,6 +51,7 @@ #include #include "trace.h" +#include "qemu/cutils.h" #include "ui/input.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" @@ -2202,6 +2203,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) GtkDisplayState *s = g_malloc0(sizeof(*s)); GdkDisplay *window_display; GtkIconTheme *theme; + char *dir; if (!gtkinit) { fprintf(stderr, "gtk initialization failed\n"); @@ -2211,7 +2213,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) s->opts = opts; theme = gtk_icon_theme_get_default(); - gtk_icon_theme_prepend_search_path(theme, CONFIG_QEMU_ICONDIR); + dir = get_relocated_path(CONFIG_QEMU_ICONDIR); + gtk_icon_theme_prepend_search_path(theme, dir); + g_free(dir); g_set_prgname("qemu"); s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -2227,7 +2231,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) * sure that we don't accidentally break implicit assumptions. */ setlocale(LC_MESSAGES, ""); setlocale(LC_CTYPE, "C.UTF-8"); - bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR); + dir = get_relocated_path(CONFIG_QEMU_LOCALEDIR); + bindtextdomain("qemu", dir); + g_free(dir); bind_textdomain_codeset("qemu", "UTF-8"); textdomain("qemu"); diff --git a/ui/sdl2.c b/ui/sdl2.c index b23a8f0a8e..abad7f981e 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" +#include "qemu/cutils.h" #include "ui/console.h" #include "ui/input.h" #include "ui/sdl2.h" @@ -795,6 +796,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) int i; SDL_SysWMinfo info; SDL_Surface *icon = NULL; + char *dir; assert(o->type == DISPLAY_TYPE_SDL); @@ -868,15 +870,18 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) } #ifdef CONFIG_SDL_IMAGE - icon = IMG_Load(CONFIG_QEMU_ICONDIR "/hicolor/128x128/apps/qemu.png"); + dir = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/128x128/apps/qemu.png"); + icon = IMG_Load(dir); #else /* Load a 32x32x4 image. White pixels are transparent. */ - icon = SDL_LoadBMP(CONFIG_QEMU_ICONDIR "/hicolor/32x32/apps/qemu.bmp"); + dir = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/32x32/apps/qemu.bmp"); + icon = SDL_LoadBMP(dir); if (icon) { uint32_t colorkey = SDL_MapRGB(icon->format, 255, 255, 255); SDL_SetColorKey(icon, SDL_TRUE, colorkey); } #endif + g_free(dir); if (icon) { SDL_SetWindowIcon(sdl2_console[0].real_window, icon); } From d17f305a2649fccdc50956b3381456a8fd318903 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2020 12:17:01 +0200 Subject: [PATCH 51/86] configure: use a platform-neutral prefix Now that the installation is relocatable, there is no need to compile a Windows-format prefix into Win32 binaries. Instead, the prefix will only be used to compute installation-relative paths, and it can be any string. Drop the "Program Files" path completely: it is only usable on English versions of Windows; therefore, using the NSIS installer to get the "correct" path to the Program Files folder is recommended, and NSIS works just as well with any prefix. Signed-off-by: Paolo Bonzini --- configure | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 803a97627b..ca9b458ea0 100755 --- a/configure +++ b/configure @@ -969,7 +969,7 @@ if test "$mingw32" = "yes" ; then # MinGW needs -mthreads for TLS and macro _MT. CFLAGS="-mthreads $CFLAGS" write_c_skeleton; - prefix="c:/Program Files/QEMU" + prefix="/qemu" qemu_suffix="" libs_qga="-lws2_32 -lwinmm -lpowrprof -lwtsapi32 -lwininet -liphlpapi -lnetapi32 $libs_qga" fi @@ -7795,17 +7795,9 @@ echo "strip = $(meson_quote $strip)" >> $cross echo "windres = $(meson_quote $windres)" >> $cross if test -n "$cross_prefix"; then cross_arg="--cross-file config-meson.cross" - # Hack: Meson expects an absolute path for the *build* machine - # for the prefix, so add a slash in front of a Windows path that - # includes a drive letter. - # - # See https://github.com/mesonbuild/meson/issues/7577. echo "[host_machine]" >> $cross if test "$mingw32" = "yes" ; then echo "system = 'windows'" >> $cross - case $prefix in - ?:*) pre_prefix=/ ;; - esac fi if test "$linux" = "yes" ; then echo "system = 'linux'" >> $cross @@ -7834,16 +7826,16 @@ mv $cross config-meson.cross rm -rf meson-private meson-info meson-logs NINJA=${ninja:-$PWD/ninjatool} $meson setup \ - --prefix "${pre_prefix}$prefix" \ - --libdir "${pre_prefix}$libdir" \ - --libexecdir "${pre_prefix}$libexecdir" \ - --bindir "${pre_prefix}$bindir" \ - --includedir "${pre_prefix}$includedir" \ - --datadir "${pre_prefix}$datadir" \ - --mandir "${pre_prefix}$mandir" \ - --sysconfdir "${pre_prefix}$sysconfdir" \ - --localstatedir "${pre_prefix}$local_statedir" \ - -Ddocdir="${pre_prefix}$docdir" \ + --prefix "$prefix" \ + --libdir "$libdir" \ + --libexecdir "$libexecdir" \ + --bindir "$bindir" \ + --includedir "$includedir" \ + --datadir "$datadir" \ + --mandir "$mandir" \ + --sysconfdir "$sysconfdir" \ + --localstatedir "$local_statedir" \ + -Ddocdir="$docdir" \ -Dqemu_suffix="$qemu_suffix" \ -Doptimization=$(if test "$debug" = yes; then echo 0; else echo 2; fi) \ -Ddebug=$(if test "$debug_info" = yes; then echo true; else echo false; fi) \ From b2a3b8d787efb24091fd6141bc72122690dcb1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 22 Jul 2020 10:25:17 +0200 Subject: [PATCH 52/86] hw/i386/q35: Remove unreachable Xen code on Q35 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xen accelerator requires specific changes to a machine to be able to use it. See for example the 'Xen PC' machine configure its PCI bus calling pc_xen_hvm_init_pci(). There is no 'Xen Q35' machine declared. This code was probably added while introducing the Q35 machine, based on the existing PC machine (see commit df2d8b3ed4 "Introduce q35 pc based chipset emulator"). Remove the unreachable code to simplify this file. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Anthony PERARD Message-Id: <20200722082517.18708-1-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc_q35.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index e14d1446be..491ab53d74 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -34,9 +34,7 @@ #include "sysemu/arch_init.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/rtc/mc146818rtc.h" -#include "hw/xen/xen.h" #include "sysemu/kvm.h" -#include "sysemu/xen.h" #include "hw/kvm/clock.h" #include "hw/pci-host/q35.h" #include "hw/qdev-properties.h" @@ -179,10 +177,6 @@ static void pc_q35_init(MachineState *machine) x86ms->below_4g_mem_size = machine->ram_size; } - if (xen_enabled()) { - xen_hvm_init(pcms, &ram_memory); - } - x86_cpus_init(x86ms, pcmc->default_cpu_version); kvmclock_create(); @@ -208,10 +202,7 @@ static void pc_q35_init(MachineState *machine) } /* allocate ram and load rom/bios */ - if (!xen_enabled()) { - pc_memory_init(pcms, get_system_memory(), - rom_memory, &ram_memory); - } + pc_memory_init(pcms, get_system_memory(), rom_memory, &ram_memory); /* create pci host bus */ q35_host = Q35_HOST_DEVICE(qdev_new(TYPE_Q35_HOST_DEVICE)); @@ -271,7 +262,7 @@ static void pc_q35_init(MachineState *machine) assert(pcms->vmport != ON_OFF_AUTO__MAX); if (pcms->vmport == ON_OFF_AUTO_AUTO) { - pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; + pcms->vmport = ON_OFF_AUTO_ON; } /* init basic PC hardware */ From 4174495408afdf27b6bfb32701c3fd9775e6bca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 6 Aug 2020 17:07:26 +0200 Subject: [PATCH 53/86] exec: Remove MemoryRegion::global_locking field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last uses of memory_region_clear_global_locking() have been removed in commit 7070e085d4 ("acpi: mark PMTIMER as unlocked") and commit 08565552f7 ("cputlb: Move NOTDIRTY handling from I/O path to TLB path"). Remove memory_region_clear_global_locking() and the now unused 'global_locking' field in MemoryRegion. Reported-by: Alexander Bulekov Suggested-by: Stefan Hajnoczi Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Message-Id: <20200806150726.962-1-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- accel/tcg/cputlb.c | 4 ++-- exec.c | 2 +- include/exec/memory.h | 14 -------------- softmmu/memory.c | 6 ------ 4 files changed, 3 insertions(+), 23 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index aaf8e46ae5..2bbbb3ab29 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1053,7 +1053,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, cpu_io_recompile(cpu, retaddr); } - if (mr->global_locking && !qemu_mutex_iothread_locked()) { + if (!qemu_mutex_iothread_locked()) { qemu_mutex_lock_iothread(); locked = true; } @@ -1114,7 +1114,7 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, */ save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset); - if (mr->global_locking && !qemu_mutex_iothread_locked()) { + if (!qemu_mutex_iothread_locked()) { qemu_mutex_lock_iothread(); locked = true; } diff --git a/exec.c b/exec.c index 3f5deb35ff..c088559d94 100644 --- a/exec.c +++ b/exec.c @@ -3137,7 +3137,7 @@ static bool prepare_mmio_access(MemoryRegion *mr) bool unlocked = !qemu_mutex_iothread_locked(); bool release_lock = false; - if (unlocked && mr->global_locking) { + if (unlocked) { qemu_mutex_lock_iothread(); unlocked = false; release_lock = true; diff --git a/include/exec/memory.h b/include/exec/memory.h index e22f5f5bb7..dee0985162 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -404,7 +404,6 @@ struct MemoryRegion { bool nonvolatile; bool rom_device; bool flush_coalesced_mmio; - bool global_locking; uint8_t dirty_log_mask; bool is_iommu; RAMBlock *ram_block; @@ -1738,19 +1737,6 @@ void memory_region_set_flush_coalesced(MemoryRegion *mr); */ void memory_region_clear_flush_coalesced(MemoryRegion *mr); -/** - * memory_region_clear_global_locking: Declares that access processing does - * not depend on the QEMU global lock. - * - * By clearing this property, accesses to the memory region will be processed - * outside of QEMU's global lock (unless the lock is held on when issuing the - * access request). In this case, the device model implementing the access - * handlers is responsible for synchronization of concurrency. - * - * @mr: the memory region to be updated. - */ -void memory_region_clear_global_locking(MemoryRegion *mr); - /** * memory_region_add_eventfd: Request an eventfd to be triggered when a word * is written to a location. diff --git a/softmmu/memory.c b/softmmu/memory.c index da5f90f141..fa280a19f7 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -1221,7 +1221,6 @@ static void memory_region_initfn(Object *obj) mr->ops = &unassigned_mem_ops; mr->enabled = true; mr->romd_mode = true; - mr->global_locking = true; mr->destructor = memory_region_destructor_none; QTAILQ_INIT(&mr->subregions); QTAILQ_INIT(&mr->coalesced); @@ -2277,11 +2276,6 @@ void memory_region_clear_flush_coalesced(MemoryRegion *mr) } } -void memory_region_clear_global_locking(MemoryRegion *mr) -{ - mr->global_locking = false; -} - static bool userspace_eventfd_warning; void memory_region_add_eventfd(MemoryRegion *mr, From fb4176d0e89fbe2be641827f2037883d99b1e94f Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Thu, 17 Sep 2020 19:02:12 +0200 Subject: [PATCH 54/86] checkpatch: avoid error on cover letter files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running checkpatch on a directory that contains a cover letter reports this error: Checking /tmp/tmpbnngauy3/0000-cover-letter.patch... ERROR: Does not appear to be a unified-diff format patch total: 1 errors, 0 warnings, 0 lines checked Let's skip cover letter as it is already done in the Linux kernel commits 06330fc40e3f ("checkpatch: avoid NOT_UNIFIED_DIFF errors on cover-letter.patch files") and a08ffbef4ab7 ("checkpatch: fix ignoring cover-letter logic"). Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Stefano Garzarella Message-Id: <20200917170212.92672-1-sgarzare@redhat.com> Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1ba8a3810b..ca4445ffe9 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3005,7 +3005,7 @@ sub process { return 1; } - if (!$is_patch) { + if (!$is_patch && $filename !~ /cover-letter\.patch$/) { ERROR("Does not appear to be a unified-diff format patch\n"); } From 6e01884c3694807fd39fe0aab9e5f7d5e6c06969 Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Fri, 18 Sep 2020 14:03:54 +0100 Subject: [PATCH 55/86] meson: fix installation of keymaps Signed-off-by: Anthony PERARD Message-Id: <20200918130354.1879275-1-anthony.perard@citrix.com> Signed-off-by: Paolo Bonzini --- pc-bios/keymaps/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build index 2e2e0dfa3b..05eda6c0d2 100644 --- a/pc-bios/keymaps/meson.build +++ b/pc-bios/keymaps/meson.build @@ -47,6 +47,7 @@ foreach km, args: keymaps build_by_default: true, output: km, command: [native_qemu_keymap, '-f', '@OUTPUT@', args.split()], + install: true, install_dir: qemu_datadir / 'keymaps') else # copy from source tree @@ -55,6 +56,7 @@ foreach km, args: keymaps input: km, output: km, command: ['cp', '@INPUT@', '@OUTPUT@'], + install: true, install_dir: qemu_datadir / 'keymaps') endif endforeach From ff9ed62b90c3cc337c9e6317d65cc9a9c84f07ce Mon Sep 17 00:00:00 2001 From: Alexander Bulekov Date: Wed, 9 Sep 2020 18:05:16 -0400 Subject: [PATCH 56/86] oss-fuzz: move linker arg to fix coverage-build The order of the add_project_link_arguments calls impacts which arguments are placed between --start-group and --end-group. OSS-Fuzz coverage builds seem to just add these to CFLAGS: -fprofile-instr-generate -fcoverage-mapping pthread -Wl,--no-as-needed -Wl,-ldl -Wl,-lm Wno-unused-command-line-argument The -Wl,-ldl flag that is enough to shift the fork_fuzz.ld linker-script back into the linker group. Move the linker-script meson call before the other calls to make sure the flag is placed correctly. Signed-off-by: Alexander Bulekov Message-Id: <20200909220516.614222-1-alxndr@bu.edu> Signed-off-by: Paolo Bonzini --- meson.build | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index b3133cf39d..3161c1f037 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,14 @@ configure_file(input: files('scripts/ninjatool.py'), # Compiler flags # ################## +# Specify linker-script with add_project_link_arguments so that it is not placed +# within a linker --start-group/--end-group pair +if 'CONFIG_FUZZ' in config_host + add_project_link_arguments(['-Wl,-T,', + (meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')], + native: false, language: ['c', 'cpp', 'objc']) +endif + add_project_arguments(config_host['QEMU_CFLAGS'].split(), native: false, language: ['c', 'objc']) add_project_arguments(config_host['QEMU_CXXFLAGS'].split(), @@ -63,13 +71,6 @@ add_project_link_arguments(config_host['QEMU_LDFLAGS'].split(), add_project_arguments(config_host['QEMU_INCLUDES'].split(), language: ['c', 'cpp', 'objc']) -# Specify linker-script with add_project_link_arguments so that it is not placed -# within a linker --start-group/--end-group pair -if 'CONFIG_FUZZ' in config_host - add_project_link_arguments(['-Wl,-T,', - (meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')], - native: false, language: ['c', 'cpp', 'objc']) -endif link_language = meson.get_external_property('link_language', 'cpp') if link_language == 'cpp' From 2c243053060f7fd47b71dcb6e3b80346b89c796b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Sep 2020 10:34:47 -0400 Subject: [PATCH 57/86] tests/tcg: reinstate or replace desired parts of rules.mak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 660f79309303d696531ffb394719dfab3e0c42c0 was a bit overzealous with respect to tests/tcg, which needed quiet-command and $(BUILD_DIR). Reinstate quiet-command, and replace $(BUILD_DIR) with just the current directory. Reported-by: Alex Bennée Signed-off-by: Paolo Bonzini --- tests/tcg/Makefile.qemu | 13 ++++++++++++- tests/tcg/configure.sh | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu index 0332bad10f..c096c611a2 100644 --- a/tests/tcg/Makefile.qemu +++ b/tests/tcg/Makefile.qemu @@ -11,9 +11,20 @@ # The configure script fills in extra information about # useful docker images or alternative compiler flags. +# Usage: $(call quiet-command,command and args,"NAME","args to print") +# This will run "command and args", and either: +# if V=1 just print the whole command and args +# otherwise print the 'quiet' output in the format " NAME args to print" +# NAME should be a short name of the command, 7 letters or fewer. +# If called with only a single argument, will print nothing in quiet mode. +quiet-command-run = $(if $(V),,$(if $2,printf " %-7s %s\n" $2 $3 && ))$1 +quiet-@ = $(if $(V),,@) +quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3) + CROSS_CC_GUEST:= DOCKER_IMAGE:= --include $(BUILD_DIR)/tests/tcg/config-$(TARGET).mak + +-include tests/tcg/config-$(TARGET).mak GUEST_BUILD= TCG_MAKE=../Makefile.target diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index 598a50cd4f..be51bdb5a4 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -193,11 +193,11 @@ for target in $target_list; do case $target in *-linux-user | *-bsd-user) echo "CONFIG_USER_ONLY=y" >> $config_target_mak - echo "QEMU=\$(BUILD_DIR)/qemu-$arch" >> $config_target_mak + echo "QEMU=$PWD/qemu-$arch" >> $config_target_mak ;; *-softmmu) echo "CONFIG_SOFTMMU=y" >> $config_target_mak - echo "QEMU=\$(BUILD_DIR)/qemu-system-$arch" >> $config_target_mak + echo "QEMU=$PWD/qemu-system-$arch" >> $config_target_mak ;; esac From b057f0961b10a5b052a81047d887a95ce206e00c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 11 Sep 2020 09:32:02 -0400 Subject: [PATCH 58/86] smp: drop support for deprecated (invalid topologies) it's was deprecated since 3.1 Support for invalid topologies is removed, the user must ensure that topologies described with -smp include all possible cpus, i.e. (sockets * cores * threads) == maxcpus or QEMU will exit with error. Signed-off-by: Igor Mammedov Acked-by: Message-Id: <20200911133202.938754-1-imammedo@redhat.com> Signed-off-by: Paolo Bonzini --- docs/system/deprecated.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 716f6aa315..da862201ba 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -646,6 +646,19 @@ as ignored. Currently, users are responsible for making sure the backing storage specified with ``-mem-path`` can actually provide the guest RAM configured with ``-m`` and QEMU fails to start up if RAM allocation is unsuccessful. +``-smp`` (invalid topologies) (removed 5.2) +''''''''''''''''''''''''''''''''''''''''''' + +CPU topology properties should describe whole machine topology including +possible CPUs. + +However, historically it was possible to start QEMU with an incorrect topology +where *n* <= *sockets* * *cores* * *threads* < *maxcpus*, +which could lead to an incorrect topology enumeration by the guest. +Support for invalid topologies is removed, the user must ensure +topologies described with -smp include all possible cpus, i.e. +*sockets* * *cores* * *threads* = *maxcpus*. + Block devices ------------- From d96aa5db4f6723222b314af86a6a92a7941e1b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 14 Sep 2020 12:31:09 +0200 Subject: [PATCH 59/86] char: fix logging when chardev write fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The qemu_chr_write_buffer() method sends data to the chardev backend for writing, and then also writes to the log file. In case the chardev backend only writes part of the data buffer, we need to make sure we only log the same subset. qemu_chr_write_buffer() will be invoked again later to write the rest of the buffer. In the case the chardev backend returns an error though, no further attempts to likely to be made to write the data. We must therefore write the entire buffer to the log immediately. An example where this is important is with the socket backend. This will return -1 for all writes if no client is currently connected. We still wish to write data to the log file when no client is present though. This used to work because the chardev would return "len" to pretend it had written all data when no client is connected, but this changed to return an error in commit 271094474b65de1ad7aaf729938de3d9b9d0d36f Author: Dima Stepanov Date: Thu May 28 12:11:18 2020 +0300 char-socket: return -1 in case of disconnect during tcp_chr_write and this broke the logging, resulting in all data being discarded when no client is present. Fixes: https://bugs.launchpad.net/qemu/+bug/1893691 Signed-off-by: Daniel P. Berrangé Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- chardev/char.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/chardev/char.c b/chardev/char.c index 6b85099c03..78553125d3 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -138,7 +138,20 @@ static int qemu_chr_write_buffer(Chardev *s, } } if (*offset > 0) { + /* + * If some data was written by backend, we should + * only log what was actually written. This method + * may be invoked again to write the remaining + * method, thus we'll log the remainder at that time. + */ qemu_chr_write_log(s, buf, *offset); + } else if (res < 0) { + /* + * If a fatal error was reported by the backend, + * assume this method won't be invoked again with + * this buffer, so log it all right away. + */ + qemu_chr_write_log(s, buf, len); } qemu_mutex_unlock(&s->chr_write_lock); From 1827c35b6bde98a0f8e4f09b03d3a6dd3bbf37a2 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:18 -0400 Subject: [PATCH 60/86] qom: Document all function parameters in doc comments kernel-doc requires all function parameters to be documented, so document them all. Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-2-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 47 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 9b01888726..77e6887b86 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1179,6 +1179,11 @@ Object *object_dynamic_cast(Object *obj, const char *typename); /** * object_dynamic_cast_assert: + * @obj: The object to cast. + * @typename: The @typename to cast to. + * @file: Source code file where function was called + * @line: Source code line where function was called + * @func: Name of function where this function was called * * See object_dynamic_cast() for a description of the parameters of this * function. The only difference in behavior is that this function asserts @@ -1255,6 +1260,9 @@ type_init(do_qemu_init_ ## type_array) * object_class_dynamic_cast_assert: * @klass: The #ObjectClass to attempt to cast. * @typename: The QOM typename of the class to cast to. + * @file: Source code file where function was called + * @line: Source code line where function was called + * @func: Name of function where this function was called * * See object_class_dynamic_cast() for a description of the parameters * of this function. The only difference in behavior is that this function @@ -1406,6 +1414,23 @@ ObjectProperty *object_property_try_add(Object *obj, const char *name, * object_property_add: * Same as object_property_try_add() with @errp hardcoded to * &error_abort. + * + * @obj: the object to add a property to + * @name: the name of the property. This can contain any character except for + * a forward slash. In general, you should use hyphens '-' instead of + * underscores '_' when naming properties. + * @type: the type name of the property. This namespace is pretty loosely + * defined. Sub namespaces are constructed by using a prefix and then + * to angle brackets. For instance, the type 'virtio-net-pci' in the + * 'link' namespace would be 'link'. + * @get: The getter to be called to read a property. If this is NULL, then + * the property cannot be read. + * @set: the setter to be called to write a property. If this is NULL, + * then the property cannot be written. + * @release: called when the property is removed from the object. This is + * meant to allow a property to free its opaque upon object + * destruction. This may be NULL. + * @opaque: an opaque pointer to pass to the callbacks for the property */ ObjectProperty *object_property_add(Object *obj, const char *name, const char *type, @@ -1517,6 +1542,7 @@ typedef struct ObjectPropertyIterator { /** * object_property_iter_init: + * @iter: the iterator instance * @obj: the object * * Initializes an iterator for traversing all properties @@ -1545,6 +1571,7 @@ void object_property_iter_init(ObjectPropertyIterator *iter, /** * object_class_property_iter_init: + * @iter: the iterator instance * @klass: the class * * Initializes an iterator for traversing all properties @@ -1592,6 +1619,7 @@ bool object_property_get(Object *obj, const char *name, Visitor *v, /** * object_property_set_str: + * @obj: the object * @name: the name of the property * @value: the value to be written to the property * @errp: returns an error if this function fails @@ -1618,6 +1646,7 @@ char *object_property_get_str(Object *obj, const char *name, /** * object_property_set_link: + * @obj: the object * @name: the name of the property * @value: the value to be written to the property * @errp: returns an error if this function fails @@ -1648,6 +1677,7 @@ Object *object_property_get_link(Object *obj, const char *name, /** * object_property_set_bool: + * @obj: the object * @name: the name of the property * @value: the value to be written to the property * @errp: returns an error if this function fails @@ -1673,6 +1703,7 @@ bool object_property_get_bool(Object *obj, const char *name, /** * object_property_set_int: + * @obj: the object * @name: the name of the property * @value: the value to be written to the property * @errp: returns an error if this function fails @@ -1698,6 +1729,7 @@ int64_t object_property_get_int(Object *obj, const char *name, /** * object_property_set_uint: + * @obj: the object * @name: the name of the property * @value: the value to be written to the property * @errp: returns an error if this function fails @@ -1821,6 +1853,7 @@ Object *object_get_internal_root(void); /** * object_get_canonical_path_component: + * @obj: the object * * Returns: The final component in the object's canonical path. The canonical * path is the path within the composition tree starting from the root. @@ -1830,6 +1863,7 @@ const char *object_get_canonical_path_component(const Object *obj); /** * object_get_canonical_path: + * @obj: the object * * Returns: The canonical path for a object, newly allocated. This is * the path within the composition tree starting from the root. Use @@ -1919,6 +1953,10 @@ ObjectProperty *object_property_try_add_child(Object *obj, const char *name, /** * object_property_add_child: + * @obj: the object to add a property to + * @name: the name of the property + * @child: the child object + * * Same as object_property_try_add_child() with @errp hardcoded to * &error_abort */ @@ -1936,13 +1974,17 @@ typedef enum { /** * object_property_allow_set_link: + * @obj: the object to add a property to + * @name: the name of the property + * @child: the child object + * @errp: pointer to error object * * The default implementation of the object_property_add_link() check() * callback function. It allows the link property to be set and never returns * an error. */ -void object_property_allow_set_link(const Object *, const char *, - Object *, Error **); +void object_property_allow_set_link(const Object *obj, const char *name, + Object *child, Error **errp); /** * object_property_add_link: @@ -2036,6 +2078,7 @@ ObjectProperty *object_class_property_add_bool(ObjectClass *klass, * @obj: the object to add a property to * @name: the name of the property * @typename: the name of the enum data type + * @lookup: enum value namelookup table * @get: the getter or %NULL if the property is write-only. * @set: the setter or %NULL if the property is read-only * From 11e1c3addf12a964d785cc72153f0d2acc5f6fc9 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:19 -0400 Subject: [PATCH 61/86] qom: Use kernel-doc private/public tags in structs Use kernel-doc syntax for indicating private and public struct fields. Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-3-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 77e6887b86..dd8f4496fc 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -520,7 +520,7 @@ typedef void (ObjectFree)(void *obj); */ struct ObjectClass { - /*< private >*/ + /* private: */ Type type; GSList *interfaces; @@ -546,7 +546,7 @@ struct ObjectClass */ struct Object { - /*< private >*/ + /* private: */ ObjectClass *class; ObjectFree *free; GHashTable *properties; @@ -908,7 +908,7 @@ struct InterfaceInfo { struct InterfaceClass { ObjectClass parent_class; - /*< private >*/ + /* private: */ ObjectClass *concrete_class; Type interface_type; }; From 78170df8274128f4f1cdbb938e8f891b227af7cb Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:20 -0400 Subject: [PATCH 62/86] qom: Use ``code`` Sphinx syntax where appropriate Replace gtkdoc markup with Sphinx ``code`` syntax. Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-4-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index dd8f4496fc..e1871f08be 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -203,8 +203,8 @@ typedef struct InterfaceInfo InterfaceInfo; * an interface instance should always be of incomplete type in order to be * sure it cannot be dereferenced. That is, you should define the * 'typedef struct SomethingIf SomethingIf' so that you can pass around - * 'SomethingIf *si' arguments, but not define a 'struct SomethingIf { ... }'. - * The only things you can validly do with a 'SomethingIf *' are to pass it as + * ``SomethingIf *si`` arguments, but not define a ``struct SomethingIf { ... }``. + * The only things you can validly do with a ``SomethingIf *`` are to pass it as * an argument to a method on its corresponding SomethingIfClass, or to * dynamically cast it to an object that implements the interface. * @@ -301,7 +301,7 @@ typedef struct InterfaceInfo InterfaceInfo; * * Alternatively, object_class_by_name() can be used to obtain the class and * its non-overridden methods for a specific type. This would correspond to - * |[ MyClass::method(...) ]| in C++. + * ``MyClass::method(...)`` in C++. * * The first example of such a QOM method was #CPUClass.reset, * another example is #DeviceClass.realize. From ed799805d00ccdda45eb8441c7d929624d9e98a6 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:21 -0400 Subject: [PATCH 63/86] qom: Add kernel-doc markup to introduction doc comment Add DOC: section keyword to introduction doc comment, so it will be rendered by kernel-doc. Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-5-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index e1871f08be..7747a1e3d8 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -29,9 +29,7 @@ typedef struct InterfaceInfo InterfaceInfo; #define TYPE_OBJECT "object" /** - * SECTION:object.h - * @title:Base Object Type System - * @short_description: interfaces for creating new types and objects + * DOC: * * The QEMU Object Model provides a framework for registering user creatable * types and instantiating objects from those types. QOM provides the following From 881444687571d8b23f308f76bef326ab860685b4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:22 -0400 Subject: [PATCH 64/86] qom: Reformat section titles using Sphinx syntax Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-6-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 7747a1e3d8..7b5800959a 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -120,7 +120,8 @@ typedef struct InterfaceInfo InterfaceInfo; * * * - * # Class Initialization # + * Class Initialization + * ==================== * * Before an object is initialized, the class for the object must be * initialized. There is only one class object for all instance objects @@ -193,7 +194,8 @@ typedef struct InterfaceInfo InterfaceInfo; * * * - * # Interfaces # + * Interfaces + * ========== * * Interfaces allow a limited form of multiple inheritance. Instances are * similar to normal types except for the fact that are only defined by @@ -206,7 +208,8 @@ typedef struct InterfaceInfo InterfaceInfo; * an argument to a method on its corresponding SomethingIfClass, or to * dynamically cast it to an object that implements the interface. * - * # Methods # + * Methods + * ======= * * A method is a function within the namespace scope of * a class. It usually operates on the object instance by passing it as a @@ -304,7 +307,8 @@ typedef struct InterfaceInfo InterfaceInfo; * The first example of such a QOM method was #CPUClass.reset, * another example is #DeviceClass.realize. * - * # Standard type declaration and definition macros # + * Standard type declaration and definition macros + * =============================================== * * A lot of the code outlined above follows a standard pattern and naming * convention. To reduce the amount of boilerplate code that needs to be From 9bbfd245c3db021eff9f17b446404a283c302f11 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:23 -0400 Subject: [PATCH 65/86] qom: Indent existing code examples This indents existing code examples that are not indented yet, just to make future conversion to Sphinx markup easier to review. Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-7-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 312 +++++++++++++++++++++---------------------- 1 file changed, 156 insertions(+), 156 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 7b5800959a..099a356be7 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -41,34 +41,34 @@ typedef struct InterfaceInfo InterfaceInfo; * * * Creating a minimal type - * - * #include "qdev.h" + * + * #include "qdev.h" * - * #define TYPE_MY_DEVICE "my-device" + * #define TYPE_MY_DEVICE "my-device" * - * // No new virtual functions: we can reuse the typedef for the - * // superclass. - * typedef DeviceClass MyDeviceClass; - * typedef struct MyDevice - * { - * DeviceState parent; + * // No new virtual functions: we can reuse the typedef for the + * // superclass. + * typedef DeviceClass MyDeviceClass; + * typedef struct MyDevice + * { + * DeviceState parent; * - * int reg0, reg1, reg2; - * } MyDevice; + * int reg0, reg1, reg2; + * } MyDevice; * - * static const TypeInfo my_device_info = { - * .name = TYPE_MY_DEVICE, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDevice), - * }; + * static const TypeInfo my_device_info = { + * .name = TYPE_MY_DEVICE, + * .parent = TYPE_DEVICE, + * .instance_size = sizeof(MyDevice), + * }; * - * static void my_device_register_types(void) - * { - * type_register_static(&my_device_info); - * } + * static void my_device_register_types(void) + * { + * type_register_static(&my_device_info); + * } * - * type_init(my_device_register_types) - * + * type_init(my_device_register_types) + * * * * In the above example, we create a simple type that is described by #TypeInfo. @@ -79,22 +79,22 @@ typedef struct InterfaceInfo InterfaceInfo; * DEFINE_TYPES() * * - * - * static const TypeInfo device_types_info[] = { - * { - * .name = TYPE_MY_DEVICE_A, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDeviceA), - * }, - * { - * .name = TYPE_MY_DEVICE_B, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDeviceB), - * }, - * }; + * + * static const TypeInfo device_types_info[] = { + * { + * .name = TYPE_MY_DEVICE_A, + * .parent = TYPE_DEVICE, + * .instance_size = sizeof(MyDeviceA), + * }, + * { + * .name = TYPE_MY_DEVICE_B, + * .parent = TYPE_DEVICE, + * .instance_size = sizeof(MyDeviceB), + * }, + * }; * - * DEFINE_TYPES(device_types_info) - * + * DEFINE_TYPES(device_types_info) + * * * * Every type has an #ObjectClass associated with it. #ObjectClass derivatives @@ -143,22 +143,22 @@ typedef struct InterfaceInfo InterfaceInfo; * * * Overriding a virtual function - * - * #include "qdev.h" + * + * #include "qdev.h" * - * void my_device_class_init(ObjectClass *klass, void *class_data) - * { - * DeviceClass *dc = DEVICE_CLASS(klass); - * dc->reset = my_device_reset; - * } + * void my_device_class_init(ObjectClass *klass, void *class_data) + * { + * DeviceClass *dc = DEVICE_CLASS(klass); + * dc->reset = my_device_reset; + * } * - * static const TypeInfo my_device_info = { - * .name = TYPE_MY_DEVICE, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDevice), - * .class_init = my_device_class_init, - * }; - * + * static const TypeInfo my_device_info = { + * .name = TYPE_MY_DEVICE, + * .parent = TYPE_DEVICE, + * .instance_size = sizeof(MyDevice), + * .class_init = my_device_class_init, + * }; + * * * * Introducing new virtual methods requires a class to define its own @@ -167,31 +167,31 @@ typedef struct InterfaceInfo InterfaceInfo; * * * Defining an abstract class - * - * #include "qdev.h" + * + * #include "qdev.h" * - * typedef struct MyDeviceClass - * { - * DeviceClass parent; + * typedef struct MyDeviceClass + * { + * DeviceClass parent; * - * void (*frobnicate) (MyDevice *obj); - * } MyDeviceClass; + * void (*frobnicate) (MyDevice *obj); + * } MyDeviceClass; * - * static const TypeInfo my_device_info = { - * .name = TYPE_MY_DEVICE, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDevice), - * .abstract = true, // or set a default in my_device_class_init - * .class_size = sizeof(MyDeviceClass), - * }; + * static const TypeInfo my_device_info = { + * .name = TYPE_MY_DEVICE, + * .parent = TYPE_DEVICE, + * .instance_size = sizeof(MyDevice), + * .abstract = true, // or set a default in my_device_class_init + * .class_size = sizeof(MyDeviceClass), + * }; * - * void my_device_frobnicate(MyDevice *obj) - * { - * MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj); + * void my_device_frobnicate(MyDevice *obj) + * { + * MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj); * - * klass->frobnicate(obj); - * } - * + * klass->frobnicate(obj); + * } + * * * * Interfaces @@ -236,68 +236,68 @@ typedef struct InterfaceInfo InterfaceInfo; * * * Overriding a virtual method - * - * typedef struct MyState MyState; + * + * typedef struct MyState MyState; * - * typedef void (*MyDoSomething)(MyState *obj); + * typedef void (*MyDoSomething)(MyState *obj); * - * typedef struct MyClass { - * ObjectClass parent_class; + * typedef struct MyClass { + * ObjectClass parent_class; * - * MyDoSomething do_something; - * } MyClass; + * MyDoSomething do_something; + * } MyClass; * - * static void my_do_something(MyState *obj) - * { - * // do something - * } + * static void my_do_something(MyState *obj) + * { + * // do something + * } * - * static void my_class_init(ObjectClass *oc, void *data) - * { - * MyClass *mc = MY_CLASS(oc); + * static void my_class_init(ObjectClass *oc, void *data) + * { + * MyClass *mc = MY_CLASS(oc); * - * mc->do_something = my_do_something; - * } + * mc->do_something = my_do_something; + * } * - * static const TypeInfo my_type_info = { - * .name = TYPE_MY, - * .parent = TYPE_OBJECT, - * .instance_size = sizeof(MyState), - * .class_size = sizeof(MyClass), - * .class_init = my_class_init, - * }; + * static const TypeInfo my_type_info = { + * .name = TYPE_MY, + * .parent = TYPE_OBJECT, + * .instance_size = sizeof(MyState), + * .class_size = sizeof(MyClass), + * .class_init = my_class_init, + * }; * - * typedef struct DerivedClass { - * MyClass parent_class; + * typedef struct DerivedClass { + * MyClass parent_class; * - * MyDoSomething parent_do_something; - * } DerivedClass; + * MyDoSomething parent_do_something; + * } DerivedClass; * - * static void derived_do_something(MyState *obj) - * { - * DerivedClass *dc = DERIVED_GET_CLASS(obj); + * static void derived_do_something(MyState *obj) + * { + * DerivedClass *dc = DERIVED_GET_CLASS(obj); * - * // do something here - * dc->parent_do_something(obj); - * // do something else here - * } + * // do something here + * dc->parent_do_something(obj); + * // do something else here + * } * - * static void derived_class_init(ObjectClass *oc, void *data) - * { - * MyClass *mc = MY_CLASS(oc); - * DerivedClass *dc = DERIVED_CLASS(oc); + * static void derived_class_init(ObjectClass *oc, void *data) + * { + * MyClass *mc = MY_CLASS(oc); + * DerivedClass *dc = DERIVED_CLASS(oc); * - * dc->parent_do_something = mc->do_something; - * mc->do_something = derived_do_something; - * } + * dc->parent_do_something = mc->do_something; + * mc->do_something = derived_do_something; + * } * - * static const TypeInfo derived_type_info = { - * .name = TYPE_DERIVED, - * .parent = TYPE_MY, - * .class_size = sizeof(DerivedClass), - * .class_init = derived_class_init, - * }; - * + * static const TypeInfo derived_type_info = { + * .name = TYPE_DERIVED, + * .parent = TYPE_MY, + * .class_size = sizeof(DerivedClass), + * .class_init = derived_class_init, + * }; + * * * * Alternatively, object_class_by_name() can be used to obtain the class and @@ -984,24 +984,24 @@ Object *object_new(const char *typename); * * * Creating an object with properties - * - * Error *err = NULL; - * Object *obj; + * + * Error *err = NULL; + * Object *obj; * - * obj = object_new_with_props(TYPE_MEMORY_BACKEND_FILE, - * object_get_objects_root(), - * "hostmem0", - * &err, - * "share", "yes", - * "mem-path", "/dev/shm/somefile", - * "prealloc", "yes", - * "size", "1048576", - * NULL); + * obj = object_new_with_props(TYPE_MEMORY_BACKEND_FILE, + * object_get_objects_root(), + * "hostmem0", + * &err, + * "share", "yes", + * "mem-path", "/dev/shm/somefile", + * "prealloc", "yes", + * "size", "1048576", + * NULL); * - * if (!obj) { - * error_reportf_err(err, "Cannot create memory backend: "); - * } - * + * if (!obj) { + * error_reportf_err(err, "Cannot create memory backend: "); + * } + * * * * The returned object will have one stable reference maintained @@ -1053,20 +1053,20 @@ void object_apply_compat_props(Object *obj); * * * Update an object's properties - * - * Error *err = NULL; - * Object *obj = ...get / create object...; + * + * Error *err = NULL; + * Object *obj = ...get / create object...; * - * if (!object_set_props(obj, - * &err, - * "share", "yes", - * "mem-path", "/dev/shm/somefile", - * "prealloc", "yes", - * "size", "1048576", - * NULL)) { - * error_reportf_err(err, "Cannot set properties: "); - * } - * + * if (!object_set_props(obj, + * &err, + * "share", "yes", + * "mem-path", "/dev/shm/somefile", + * "prealloc", "yes", + * "size", "1048576", + * NULL)) { + * error_reportf_err(err, "Cannot set properties: "); + * } + * * * * The returned object will have one stable reference maintained @@ -1557,15 +1557,15 @@ typedef struct ObjectPropertyIterator { * * * Using object property iterators - * - * ObjectProperty *prop; - * ObjectPropertyIterator iter; + * + * ObjectProperty *prop; + * ObjectPropertyIterator iter; * - * object_property_iter_init(&iter, obj); - * while ((prop = object_property_iter_next(&iter))) { - * ... do something with prop ... - * } - * + * object_property_iter_init(&iter, obj); + * while ((prop = object_property_iter_next(&iter))) { + * ... do something with prop ... + * } + * * */ void object_property_iter_init(ObjectPropertyIterator *iter, From 6cf164c00fb3e93fa8b76372691563ec37a176ad Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:24 -0400 Subject: [PATCH 66/86] qom: Add code block markup to all code blocks Convert all example/codelisting markup to Sphinx code-block. There are a few sections where backslashes at the end of lines break code formatting. A comment was added noting that this is an issue. Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-8-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 135 ++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 79 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 099a356be7..fec78cbb67 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -31,6 +31,8 @@ typedef struct InterfaceInfo InterfaceInfo; /** * DOC: * + * .. highlight:: c + * * The QEMU Object Model provides a framework for registering user creatable * types and instantiating objects from those types. QOM provides the following * features: @@ -39,9 +41,9 @@ typedef struct InterfaceInfo InterfaceInfo; * - Support for single-inheritance of types * - Multiple inheritance of stateless interfaces * - * - * Creating a minimal type - * + * .. code-block:: c + * :caption: Creating a minimal type + * * #include "qdev.h" * * #define TYPE_MY_DEVICE "my-device" @@ -68,8 +70,6 @@ typedef struct InterfaceInfo InterfaceInfo; * } * * type_init(my_device_register_types) - * - * * * In the above example, we create a simple type that is described by #TypeInfo. * #TypeInfo describes information about the type including what it inherits @@ -78,8 +78,8 @@ typedef struct InterfaceInfo InterfaceInfo; * Alternatively several static types could be registered using helper macro * DEFINE_TYPES() * - * - * + * .. code-block:: c + * * static const TypeInfo device_types_info[] = { * { * .name = TYPE_MY_DEVICE_A, @@ -94,8 +94,6 @@ typedef struct InterfaceInfo InterfaceInfo; * }; * * DEFINE_TYPES(device_types_info) - * - * * * Every type has an #ObjectClass associated with it. #ObjectClass derivatives * are instantiated dynamically but there is only ever one instance for any @@ -108,17 +106,19 @@ typedef struct InterfaceInfo InterfaceInfo; * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a * specific type: * - * - * Typecasting macros - * + * .. kernel-doc messes up with the code block below because of the + * backslash at the end of lines. This will be fixes if we move this + * content to qom.rst. + * + * .. code-block:: c + * :caption: Typecasting macros + * * #define MY_DEVICE_GET_CLASS(obj) \ * OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE) * #define MY_DEVICE_CLASS(klass) \ * OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE) * #define MY_DEVICE(obj) \ * OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE) - * - * * * Class Initialization * ==================== @@ -141,9 +141,9 @@ typedef struct InterfaceInfo InterfaceInfo; * its virtual functions. Here is how the above example might be modified * to introduce an overridden virtual function: * - * - * Overriding a virtual function - * + * .. code-block:: c + * :caption: Overriding a virtual function + * * #include "qdev.h" * * void my_device_class_init(ObjectClass *klass, void *class_data) @@ -158,16 +158,14 @@ typedef struct InterfaceInfo InterfaceInfo; * .instance_size = sizeof(MyDevice), * .class_init = my_device_class_init, * }; - * - * * * Introducing new virtual methods requires a class to define its own * struct and to add a .class_size member to the #TypeInfo. Each method * will also have a wrapper function to call it easily: * - * - * Defining an abstract class - * + * .. code-block:: c + * :caption: Defining an abstract class + * * #include "qdev.h" * * typedef struct MyDeviceClass @@ -191,8 +189,6 @@ typedef struct InterfaceInfo InterfaceInfo; * * klass->frobnicate(obj); * } - * - * * * Interfaces * ========== @@ -230,13 +226,13 @@ typedef struct InterfaceInfo InterfaceInfo; * * To invoke the method being overridden, the preferred solution is to store * the original value in the overriding class before overriding the method. - * This corresponds to |[ {super,base}.method(...) ]| in Java and C# + * This corresponds to ``{super,base}.method(...)`` in Java and C# * respectively; this frees the overriding class from hardcoding its parent * class, which someone might choose to change at some point. * - * - * Overriding a virtual method - * + * .. code-block:: c + * :caption: Overriding a virtual method + * * typedef struct MyState MyState; * * typedef void (*MyDoSomething)(MyState *obj); @@ -297,8 +293,6 @@ typedef struct InterfaceInfo InterfaceInfo; * .class_size = sizeof(DerivedClass), * .class_init = derived_class_init, * }; - * - * * * Alternatively, object_class_by_name() can be used to obtain the class and * its non-overridden methods for a specific type. This would correspond to @@ -320,18 +314,16 @@ typedef struct InterfaceInfo InterfaceInfo; * OBJECT_DECLARE_SIMPLE_TYPE macro is suitable, and is commonly placed * in the header file: * - * - * Declaring a simple type - * + * .. code-block:: c + * :caption: Declaring a simple type + * * OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) - * - * * * This is equivalent to the following: * - * - * Expansion from declaring a simple type - * + * .. code-block:: c + * :caption: Expansion from declaring a simple type + * * typedef struct MyDevice MyDevice; * typedef struct MyDeviceClass MyDeviceClass; * @@ -347,8 +339,6 @@ typedef struct InterfaceInfo InterfaceInfo; * struct MyDeviceClass { * DeviceClass parent_class; * }; - * - * * * The 'struct MyDevice' needs to be declared separately. * If the type requires virtual functions to be declared in the class @@ -359,18 +349,16 @@ typedef struct InterfaceInfo InterfaceInfo; * To implement the type, the OBJECT_DEFINE macro family is available. * In the simple case the OBJECT_DEFINE_TYPE macro is suitable: * - * - * Defining a simple type - * + * .. code-block:: c + * :caption: Defining a simple type + * * OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) - * - * * * This is equivalent to the following: * - * - * Expansion from defining a simple type - * + * .. code-block:: c + * :caption: Expansion from defining a simple type + * * static void my_device_finalize(Object *obj); * static void my_device_class_init(ObjectClass *oc, void *data); * static void my_device_init(Object *obj); @@ -391,8 +379,6 @@ typedef struct InterfaceInfo InterfaceInfo; * type_register_static(&my_device_info); * } * type_init(my_device_register_types); - * - * * * This is sufficient to get the type registered with the type * system, and the three standard methods now need to be implemented @@ -402,24 +388,20 @@ typedef struct InterfaceInfo InterfaceInfo; * OBJECT_DEFINE_TYPE_WITH_INTERFACES() macro can be used instead. * This accepts an array of interface type names. * - * - * Defining a simple type implementing interfaces - * + * .. code-block:: c + * :caption: Defining a simple type implementing interfaces + * * OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device, * MY_DEVICE, DEVICE, * { TYPE_USER_CREATABLE }, { NULL }) - * - * * * If the type is not intended to be instantiated, then then * the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead: * - * - * Defining a simple type - * + * .. code-block:: c + * :caption: Defining a simple abstract type + * * OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) - * - * */ @@ -982,9 +964,9 @@ Object *object_new(const char *typename); * object will be marked complete once all the properties have been * processed. * - * - * Creating an object with properties - * + * .. code-block:: c + * :caption: Creating an object with properties + * * Error *err = NULL; * Object *obj; * @@ -1001,8 +983,6 @@ Object *object_new(const char *typename); * if (!obj) { * error_reportf_err(err, "Cannot create memory backend: "); * } - * - * * * The returned object will have one stable reference maintained * for as long as it is present in the object hierarchy. @@ -1051,9 +1031,9 @@ void object_apply_compat_props(Object *obj); * strings. The propname of %NULL indicates the end of the property * list. * - * - * Update an object's properties - * + * .. code-block:: c + * :caption: Update an object's properties + * * Error *err = NULL; * Object *obj = ...get / create object...; * @@ -1066,8 +1046,6 @@ void object_apply_compat_props(Object *obj); * NULL)) { * error_reportf_err(err, "Cannot set properties: "); * } - * - * * * The returned object will have one stable reference maintained * for as long as it is present in the object hierarchy. @@ -1155,10 +1133,11 @@ bool object_initialize_child_with_propsv(Object *parentobj, * object. * @type: The name of the type of the object to instantiate. * - * This is like - * object_initialize_child_with_props(parent, propname, - * child, sizeof(*child), type, - * &error_abort, NULL) + * This is like:: + * + * object_initialize_child_with_props(parent, propname, + * child, sizeof(*child), type, + * &error_abort, NULL) */ #define object_initialize_child(parent, propname, child, type) \ object_initialize_child_internal((parent), (propname), \ @@ -1555,9 +1534,9 @@ typedef struct ObjectPropertyIterator { * * Typical usage pattern would be * - * - * Using object property iterators - * + * .. code-block:: c + * :caption: Using object property iterators + * * ObjectProperty *prop; * ObjectPropertyIterator iter; * @@ -1565,8 +1544,6 @@ typedef struct ObjectPropertyIterator { * while ((prop = object_property_iter_next(&iter))) { * ... do something with prop ... * } - * - * */ void object_property_iter_init(ObjectPropertyIterator *iter, Object *obj); From cd442a45db60a1a72fcf980c24bd1227f13f8a87 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 10 Sep 2020 18:15:25 -0400 Subject: [PATCH 67/86] docs: Create docs/devel/qom.rst Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-9-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- docs/devel/index.rst | 1 + docs/devel/qom.rst | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 docs/devel/qom.rst diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 04773ce076..c34b43ec28 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -31,3 +31,4 @@ Contents: reset s390-dasd-ipl clocks + qom diff --git a/docs/devel/qom.rst b/docs/devel/qom.rst new file mode 100644 index 0000000000..dc5be79a4a --- /dev/null +++ b/docs/devel/qom.rst @@ -0,0 +1,5 @@ +=========================== +The QEMU Object Model (QOM) +=========================== + +.. kernel-doc:: include/qom/object.h From 9cb54b18e8b9814899adb7a58a6e561eae3b1913 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 23 Sep 2020 12:21:39 -0400 Subject: [PATCH 68/86] docs: Move object.h overview doc comment to qom.rst Move the whole contents of the overview doc comment from object.h to qom.rst. This makes the documentation source easier to read and edit, and also solves the backslash escaping issue at the typecasting macro examples. Signed-off-by: Eduardo Habkost Message-Id: <20200910221526.10041-10-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- docs/devel/qom.rst | 373 ++++++++++++++++++++++++++++++++++++++++++ include/qom/object.h | 377 ------------------------------------------- 2 files changed, 373 insertions(+), 377 deletions(-) diff --git a/docs/devel/qom.rst b/docs/devel/qom.rst index dc5be79a4a..0b943b2a1a 100644 --- a/docs/devel/qom.rst +++ b/docs/devel/qom.rst @@ -2,4 +2,377 @@ The QEMU Object Model (QOM) =========================== +.. highlight:: c + +The QEMU Object Model provides a framework for registering user creatable +types and instantiating objects from those types. QOM provides the following +features: + + - System for dynamically registering types + - Support for single-inheritance of types + - Multiple inheritance of stateless interfaces + +.. code-block:: c + :caption: Creating a minimal type + + #include "qdev.h" + + #define TYPE_MY_DEVICE "my-device" + + // No new virtual functions: we can reuse the typedef for the + // superclass. + typedef DeviceClass MyDeviceClass; + typedef struct MyDevice + { + DeviceState parent; + + int reg0, reg1, reg2; + } MyDevice; + + static const TypeInfo my_device_info = { + .name = TYPE_MY_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(MyDevice), + }; + + static void my_device_register_types(void) + { + type_register_static(&my_device_info); + } + + type_init(my_device_register_types) + +In the above example, we create a simple type that is described by #TypeInfo. +#TypeInfo describes information about the type including what it inherits +from, the instance and class size, and constructor/destructor hooks. + +Alternatively several static types could be registered using helper macro +DEFINE_TYPES() + +.. code-block:: c + + static const TypeInfo device_types_info[] = { + { + .name = TYPE_MY_DEVICE_A, + .parent = TYPE_DEVICE, + .instance_size = sizeof(MyDeviceA), + }, + { + .name = TYPE_MY_DEVICE_B, + .parent = TYPE_DEVICE, + .instance_size = sizeof(MyDeviceB), + }, + }; + + DEFINE_TYPES(device_types_info) + +Every type has an #ObjectClass associated with it. #ObjectClass derivatives +are instantiated dynamically but there is only ever one instance for any +given type. The #ObjectClass typically holds a table of function pointers +for the virtual methods implemented by this type. + +Using object_new(), a new #Object derivative will be instantiated. You can +cast an #Object to a subclass (or base-class) type using +object_dynamic_cast(). You typically want to define macro wrappers around +OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a +specific type: + +.. code-block:: c + :caption: Typecasting macros + + #define MY_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE) + #define MY_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE) + #define MY_DEVICE(obj) \ + OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE) + +Class Initialization +==================== + +Before an object is initialized, the class for the object must be +initialized. There is only one class object for all instance objects +that is created lazily. + +Classes are initialized by first initializing any parent classes (if +necessary). After the parent class object has initialized, it will be +copied into the current class object and any additional storage in the +class object is zero filled. + +The effect of this is that classes automatically inherit any virtual +function pointers that the parent class has already initialized. All +other fields will be zero filled. + +Once all of the parent classes have been initialized, #TypeInfo::class_init +is called to let the class being instantiated provide default initialize for +its virtual functions. Here is how the above example might be modified +to introduce an overridden virtual function: + +.. code-block:: c + :caption: Overriding a virtual function + + #include "qdev.h" + + void my_device_class_init(ObjectClass *klass, void *class_data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = my_device_reset; + } + + static const TypeInfo my_device_info = { + .name = TYPE_MY_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(MyDevice), + .class_init = my_device_class_init, + }; + +Introducing new virtual methods requires a class to define its own +struct and to add a .class_size member to the #TypeInfo. Each method +will also have a wrapper function to call it easily: + +.. code-block:: c + :caption: Defining an abstract class + + #include "qdev.h" + + typedef struct MyDeviceClass + { + DeviceClass parent; + + void (*frobnicate) (MyDevice *obj); + } MyDeviceClass; + + static const TypeInfo my_device_info = { + .name = TYPE_MY_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(MyDevice), + .abstract = true, // or set a default in my_device_class_init + .class_size = sizeof(MyDeviceClass), + }; + + void my_device_frobnicate(MyDevice *obj) + { + MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj); + + klass->frobnicate(obj); + } + +Interfaces +========== + +Interfaces allow a limited form of multiple inheritance. Instances are +similar to normal types except for the fact that are only defined by +their classes and never carry any state. As a consequence, a pointer to +an interface instance should always be of incomplete type in order to be +sure it cannot be dereferenced. That is, you should define the +'typedef struct SomethingIf SomethingIf' so that you can pass around +``SomethingIf *si`` arguments, but not define a ``struct SomethingIf { ... }``. +The only things you can validly do with a ``SomethingIf *`` are to pass it as +an argument to a method on its corresponding SomethingIfClass, or to +dynamically cast it to an object that implements the interface. + +Methods +======= + +A method is a function within the namespace scope of +a class. It usually operates on the object instance by passing it as a +strongly-typed first argument. +If it does not operate on an object instance, it is dubbed +class method. + +Methods cannot be overloaded. That is, the #ObjectClass and method name +uniquely identity the function to be called; the signature does not vary +except for trailing varargs. + +Methods are always virtual. Overriding a method in +#TypeInfo.class_init of a subclass leads to any user of the class obtained +via OBJECT_GET_CLASS() accessing the overridden function. +The original function is not automatically invoked. It is the responsibility +of the overriding class to determine whether and when to invoke the method +being overridden. + +To invoke the method being overridden, the preferred solution is to store +the original value in the overriding class before overriding the method. +This corresponds to ``{super,base}.method(...)`` in Java and C# +respectively; this frees the overriding class from hardcoding its parent +class, which someone might choose to change at some point. + +.. code-block:: c + :caption: Overriding a virtual method + + typedef struct MyState MyState; + + typedef void (*MyDoSomething)(MyState *obj); + + typedef struct MyClass { + ObjectClass parent_class; + + MyDoSomething do_something; + } MyClass; + + static void my_do_something(MyState *obj) + { + // do something + } + + static void my_class_init(ObjectClass *oc, void *data) + { + MyClass *mc = MY_CLASS(oc); + + mc->do_something = my_do_something; + } + + static const TypeInfo my_type_info = { + .name = TYPE_MY, + .parent = TYPE_OBJECT, + .instance_size = sizeof(MyState), + .class_size = sizeof(MyClass), + .class_init = my_class_init, + }; + + typedef struct DerivedClass { + MyClass parent_class; + + MyDoSomething parent_do_something; + } DerivedClass; + + static void derived_do_something(MyState *obj) + { + DerivedClass *dc = DERIVED_GET_CLASS(obj); + + // do something here + dc->parent_do_something(obj); + // do something else here + } + + static void derived_class_init(ObjectClass *oc, void *data) + { + MyClass *mc = MY_CLASS(oc); + DerivedClass *dc = DERIVED_CLASS(oc); + + dc->parent_do_something = mc->do_something; + mc->do_something = derived_do_something; + } + + static const TypeInfo derived_type_info = { + .name = TYPE_DERIVED, + .parent = TYPE_MY, + .class_size = sizeof(DerivedClass), + .class_init = derived_class_init, + }; + +Alternatively, object_class_by_name() can be used to obtain the class and +its non-overridden methods for a specific type. This would correspond to +``MyClass::method(...)`` in C++. + +The first example of such a QOM method was #CPUClass.reset, +another example is #DeviceClass.realize. + +Standard type declaration and definition macros +=============================================== + +A lot of the code outlined above follows a standard pattern and naming +convention. To reduce the amount of boilerplate code that needs to be +written for a new type there are two sets of macros to generate the +common parts in a standard format. + +A type is declared using the OBJECT_DECLARE macro family. In types +which do not require any virtual functions in the class, the +OBJECT_DECLARE_SIMPLE_TYPE macro is suitable, and is commonly placed +in the header file: + +.. code-block:: c + :caption: Declaring a simple type + + OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) + +This is equivalent to the following: + +.. code-block:: c + :caption: Expansion from declaring a simple type + + typedef struct MyDevice MyDevice; + typedef struct MyDeviceClass MyDeviceClass; + + G_DEFINE_AUTOPTR_CLEANUP_FUNC(MyDeviceClass, object_unref) + + #define MY_DEVICE_GET_CLASS(void *obj) \ + OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE) + #define MY_DEVICE_CLASS(void *klass) \ + OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE) + #define MY_DEVICE(void *obj) + OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE) + + struct MyDeviceClass { + DeviceClass parent_class; + }; + +The 'struct MyDevice' needs to be declared separately. +If the type requires virtual functions to be declared in the class +struct, then the alternative OBJECT_DECLARE_TYPE() macro can be +used. This does the same as OBJECT_DECLARE_SIMPLE_TYPE(), but without +the 'struct MyDeviceClass' definition. + +To implement the type, the OBJECT_DEFINE macro family is available. +In the simple case the OBJECT_DEFINE_TYPE macro is suitable: + +.. code-block:: c + :caption: Defining a simple type + + OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) + +This is equivalent to the following: + +.. code-block:: c + :caption: Expansion from defining a simple type + + static void my_device_finalize(Object *obj); + static void my_device_class_init(ObjectClass *oc, void *data); + static void my_device_init(Object *obj); + + static const TypeInfo my_device_info = { + .parent = TYPE_DEVICE, + .name = TYPE_MY_DEVICE, + .instance_size = sizeof(MyDevice), + .instance_init = my_device_init, + .instance_finalize = my_device_finalize, + .class_size = sizeof(MyDeviceClass), + .class_init = my_device_class_init, + }; + + static void + my_device_register_types(void) + { + type_register_static(&my_device_info); + } + type_init(my_device_register_types); + +This is sufficient to get the type registered with the type +system, and the three standard methods now need to be implemented +along with any other logic required for the type. + +If the type needs to implement one or more interfaces, then the +OBJECT_DEFINE_TYPE_WITH_INTERFACES() macro can be used instead. +This accepts an array of interface type names. + +.. code-block:: c + :caption: Defining a simple type implementing interfaces + + OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device, + MY_DEVICE, DEVICE, + { TYPE_USER_CREATABLE }, { NULL }) + +If the type is not intended to be instantiated, then then +the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead: + +.. code-block:: c + :caption: Defining a simple abstract type + + OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) + + + +API Reference +------------- + .. kernel-doc:: include/qom/object.h diff --git a/include/qom/object.h b/include/qom/object.h index fec78cbb67..27aaa67e63 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -28,383 +28,6 @@ typedef struct InterfaceInfo InterfaceInfo; #define TYPE_OBJECT "object" -/** - * DOC: - * - * .. highlight:: c - * - * The QEMU Object Model provides a framework for registering user creatable - * types and instantiating objects from those types. QOM provides the following - * features: - * - * - System for dynamically registering types - * - Support for single-inheritance of types - * - Multiple inheritance of stateless interfaces - * - * .. code-block:: c - * :caption: Creating a minimal type - * - * #include "qdev.h" - * - * #define TYPE_MY_DEVICE "my-device" - * - * // No new virtual functions: we can reuse the typedef for the - * // superclass. - * typedef DeviceClass MyDeviceClass; - * typedef struct MyDevice - * { - * DeviceState parent; - * - * int reg0, reg1, reg2; - * } MyDevice; - * - * static const TypeInfo my_device_info = { - * .name = TYPE_MY_DEVICE, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDevice), - * }; - * - * static void my_device_register_types(void) - * { - * type_register_static(&my_device_info); - * } - * - * type_init(my_device_register_types) - * - * In the above example, we create a simple type that is described by #TypeInfo. - * #TypeInfo describes information about the type including what it inherits - * from, the instance and class size, and constructor/destructor hooks. - * - * Alternatively several static types could be registered using helper macro - * DEFINE_TYPES() - * - * .. code-block:: c - * - * static const TypeInfo device_types_info[] = { - * { - * .name = TYPE_MY_DEVICE_A, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDeviceA), - * }, - * { - * .name = TYPE_MY_DEVICE_B, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDeviceB), - * }, - * }; - * - * DEFINE_TYPES(device_types_info) - * - * Every type has an #ObjectClass associated with it. #ObjectClass derivatives - * are instantiated dynamically but there is only ever one instance for any - * given type. The #ObjectClass typically holds a table of function pointers - * for the virtual methods implemented by this type. - * - * Using object_new(), a new #Object derivative will be instantiated. You can - * cast an #Object to a subclass (or base-class) type using - * object_dynamic_cast(). You typically want to define macro wrappers around - * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a - * specific type: - * - * .. kernel-doc messes up with the code block below because of the - * backslash at the end of lines. This will be fixes if we move this - * content to qom.rst. - * - * .. code-block:: c - * :caption: Typecasting macros - * - * #define MY_DEVICE_GET_CLASS(obj) \ - * OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE) - * #define MY_DEVICE_CLASS(klass) \ - * OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE) - * #define MY_DEVICE(obj) \ - * OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE) - * - * Class Initialization - * ==================== - * - * Before an object is initialized, the class for the object must be - * initialized. There is only one class object for all instance objects - * that is created lazily. - * - * Classes are initialized by first initializing any parent classes (if - * necessary). After the parent class object has initialized, it will be - * copied into the current class object and any additional storage in the - * class object is zero filled. - * - * The effect of this is that classes automatically inherit any virtual - * function pointers that the parent class has already initialized. All - * other fields will be zero filled. - * - * Once all of the parent classes have been initialized, #TypeInfo::class_init - * is called to let the class being instantiated provide default initialize for - * its virtual functions. Here is how the above example might be modified - * to introduce an overridden virtual function: - * - * .. code-block:: c - * :caption: Overriding a virtual function - * - * #include "qdev.h" - * - * void my_device_class_init(ObjectClass *klass, void *class_data) - * { - * DeviceClass *dc = DEVICE_CLASS(klass); - * dc->reset = my_device_reset; - * } - * - * static const TypeInfo my_device_info = { - * .name = TYPE_MY_DEVICE, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDevice), - * .class_init = my_device_class_init, - * }; - * - * Introducing new virtual methods requires a class to define its own - * struct and to add a .class_size member to the #TypeInfo. Each method - * will also have a wrapper function to call it easily: - * - * .. code-block:: c - * :caption: Defining an abstract class - * - * #include "qdev.h" - * - * typedef struct MyDeviceClass - * { - * DeviceClass parent; - * - * void (*frobnicate) (MyDevice *obj); - * } MyDeviceClass; - * - * static const TypeInfo my_device_info = { - * .name = TYPE_MY_DEVICE, - * .parent = TYPE_DEVICE, - * .instance_size = sizeof(MyDevice), - * .abstract = true, // or set a default in my_device_class_init - * .class_size = sizeof(MyDeviceClass), - * }; - * - * void my_device_frobnicate(MyDevice *obj) - * { - * MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj); - * - * klass->frobnicate(obj); - * } - * - * Interfaces - * ========== - * - * Interfaces allow a limited form of multiple inheritance. Instances are - * similar to normal types except for the fact that are only defined by - * their classes and never carry any state. As a consequence, a pointer to - * an interface instance should always be of incomplete type in order to be - * sure it cannot be dereferenced. That is, you should define the - * 'typedef struct SomethingIf SomethingIf' so that you can pass around - * ``SomethingIf *si`` arguments, but not define a ``struct SomethingIf { ... }``. - * The only things you can validly do with a ``SomethingIf *`` are to pass it as - * an argument to a method on its corresponding SomethingIfClass, or to - * dynamically cast it to an object that implements the interface. - * - * Methods - * ======= - * - * A method is a function within the namespace scope of - * a class. It usually operates on the object instance by passing it as a - * strongly-typed first argument. - * If it does not operate on an object instance, it is dubbed - * class method. - * - * Methods cannot be overloaded. That is, the #ObjectClass and method name - * uniquely identity the function to be called; the signature does not vary - * except for trailing varargs. - * - * Methods are always virtual. Overriding a method in - * #TypeInfo.class_init of a subclass leads to any user of the class obtained - * via OBJECT_GET_CLASS() accessing the overridden function. - * The original function is not automatically invoked. It is the responsibility - * of the overriding class to determine whether and when to invoke the method - * being overridden. - * - * To invoke the method being overridden, the preferred solution is to store - * the original value in the overriding class before overriding the method. - * This corresponds to ``{super,base}.method(...)`` in Java and C# - * respectively; this frees the overriding class from hardcoding its parent - * class, which someone might choose to change at some point. - * - * .. code-block:: c - * :caption: Overriding a virtual method - * - * typedef struct MyState MyState; - * - * typedef void (*MyDoSomething)(MyState *obj); - * - * typedef struct MyClass { - * ObjectClass parent_class; - * - * MyDoSomething do_something; - * } MyClass; - * - * static void my_do_something(MyState *obj) - * { - * // do something - * } - * - * static void my_class_init(ObjectClass *oc, void *data) - * { - * MyClass *mc = MY_CLASS(oc); - * - * mc->do_something = my_do_something; - * } - * - * static const TypeInfo my_type_info = { - * .name = TYPE_MY, - * .parent = TYPE_OBJECT, - * .instance_size = sizeof(MyState), - * .class_size = sizeof(MyClass), - * .class_init = my_class_init, - * }; - * - * typedef struct DerivedClass { - * MyClass parent_class; - * - * MyDoSomething parent_do_something; - * } DerivedClass; - * - * static void derived_do_something(MyState *obj) - * { - * DerivedClass *dc = DERIVED_GET_CLASS(obj); - * - * // do something here - * dc->parent_do_something(obj); - * // do something else here - * } - * - * static void derived_class_init(ObjectClass *oc, void *data) - * { - * MyClass *mc = MY_CLASS(oc); - * DerivedClass *dc = DERIVED_CLASS(oc); - * - * dc->parent_do_something = mc->do_something; - * mc->do_something = derived_do_something; - * } - * - * static const TypeInfo derived_type_info = { - * .name = TYPE_DERIVED, - * .parent = TYPE_MY, - * .class_size = sizeof(DerivedClass), - * .class_init = derived_class_init, - * }; - * - * Alternatively, object_class_by_name() can be used to obtain the class and - * its non-overridden methods for a specific type. This would correspond to - * ``MyClass::method(...)`` in C++. - * - * The first example of such a QOM method was #CPUClass.reset, - * another example is #DeviceClass.realize. - * - * Standard type declaration and definition macros - * =============================================== - * - * A lot of the code outlined above follows a standard pattern and naming - * convention. To reduce the amount of boilerplate code that needs to be - * written for a new type there are two sets of macros to generate the - * common parts in a standard format. - * - * A type is declared using the OBJECT_DECLARE macro family. In types - * which do not require any virtual functions in the class, the - * OBJECT_DECLARE_SIMPLE_TYPE macro is suitable, and is commonly placed - * in the header file: - * - * .. code-block:: c - * :caption: Declaring a simple type - * - * OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) - * - * This is equivalent to the following: - * - * .. code-block:: c - * :caption: Expansion from declaring a simple type - * - * typedef struct MyDevice MyDevice; - * typedef struct MyDeviceClass MyDeviceClass; - * - * G_DEFINE_AUTOPTR_CLEANUP_FUNC(MyDeviceClass, object_unref) - * - * #define MY_DEVICE_GET_CLASS(void *obj) \ - * OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE) - * #define MY_DEVICE_CLASS(void *klass) \ - * OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE) - * #define MY_DEVICE(void *obj) - * OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE) - * - * struct MyDeviceClass { - * DeviceClass parent_class; - * }; - * - * The 'struct MyDevice' needs to be declared separately. - * If the type requires virtual functions to be declared in the class - * struct, then the alternative OBJECT_DECLARE_TYPE() macro can be - * used. This does the same as OBJECT_DECLARE_SIMPLE_TYPE(), but without - * the 'struct MyDeviceClass' definition. - * - * To implement the type, the OBJECT_DEFINE macro family is available. - * In the simple case the OBJECT_DEFINE_TYPE macro is suitable: - * - * .. code-block:: c - * :caption: Defining a simple type - * - * OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) - * - * This is equivalent to the following: - * - * .. code-block:: c - * :caption: Expansion from defining a simple type - * - * static void my_device_finalize(Object *obj); - * static void my_device_class_init(ObjectClass *oc, void *data); - * static void my_device_init(Object *obj); - * - * static const TypeInfo my_device_info = { - * .parent = TYPE_DEVICE, - * .name = TYPE_MY_DEVICE, - * .instance_size = sizeof(MyDevice), - * .instance_init = my_device_init, - * .instance_finalize = my_device_finalize, - * .class_size = sizeof(MyDeviceClass), - * .class_init = my_device_class_init, - * }; - * - * static void - * my_device_register_types(void) - * { - * type_register_static(&my_device_info); - * } - * type_init(my_device_register_types); - * - * This is sufficient to get the type registered with the type - * system, and the three standard methods now need to be implemented - * along with any other logic required for the type. - * - * If the type needs to implement one or more interfaces, then the - * OBJECT_DEFINE_TYPE_WITH_INTERFACES() macro can be used instead. - * This accepts an array of interface type names. - * - * .. code-block:: c - * :caption: Defining a simple type implementing interfaces - * - * OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device, - * MY_DEVICE, DEVICE, - * { TYPE_USER_CREATABLE }, { NULL }) - * - * If the type is not intended to be instantiated, then then - * the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead: - * - * .. code-block:: c - * :caption: Defining a simple abstract type - * - * OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) - */ - - typedef struct ObjectProperty ObjectProperty; /** From 5650ac00d758b3bcf6840715765f8a6e5d5549a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Sep 2020 17:55:26 +0200 Subject: [PATCH 69/86] hw/i386/xen: Rename X86/PC specific function as xen_hvm_init_pc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xen_hvm_init() is only meanful to initialize a X86/PC machine, rename it as xen_hvm_init_pc(). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200908155530.249806-3-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- accel/stubs/xen-stub.c | 2 +- hw/i386/pc_piix.c | 6 +++--- hw/i386/xen/xen-hvm.c | 2 +- include/hw/xen/xen.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accel/stubs/xen-stub.c b/accel/stubs/xen-stub.c index 8ae658acff..fa3dddbce5 100644 --- a/accel/stubs/xen-stub.c +++ b/accel/stubs/xen-stub.c @@ -46,7 +46,7 @@ void xen_register_framebuffer(MemoryRegion *mr) { } -void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) +void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory) { } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 32c5d95762..9eaf8d6e0d 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -117,8 +117,8 @@ static void pc_init1(MachineState *machine, * so legacy non-PAE guests can get as much memory as possible in * the 32bit address space below 4G. * - * - Note that Xen has its own ram setp code in xen_ram_init(), - * called via xen_hvm_init(). + * - Note that Xen has its own ram setup code in xen_ram_init(), + * called via xen_hvm_init_pc(). * * Examples: * qemu -M pc-1.7 -m 4G (old default) -> 3584M low, 512M high @@ -127,7 +127,7 @@ static void pc_init1(MachineState *machine, * qemu -M pc,max-ram-below-4g=4G -m 3968M -> 3968M low (=4G-128M) */ if (xen_enabled()) { - xen_hvm_init(pcms, &ram_memory); + xen_hvm_init_pc(pcms, &ram_memory); } else { if (!pcms->max_ram_below_4g) { pcms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */ diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index a39a648ca6..91b6a30061 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -1395,7 +1395,7 @@ static int xen_map_ioreq_server(XenIOState *state) return 0; } -void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) +void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory) { MachineState *ms = MACHINE(pcms); unsigned int max_cpus = ms->smp.max_cpus; diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 771dd447f2..b2b459964c 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -30,7 +30,7 @@ qemu_irq *xen_interrupt_controller_init(void); void xenstore_store_pv_console_info(int i, struct Chardev *chr); -void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory); +void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory); void xen_register_framebuffer(struct MemoryRegion *mr); From ce6936bc2dcb3aeb868e98cfb5a984fc35a0fabe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Sep 2020 17:55:27 +0200 Subject: [PATCH 70/86] sysemu/xen: Add missing 'exec/cpu-common.h' header for ram_addr_t type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As this header use the ram_addr_t type, it has to include "exec/cpu-common.h" to avoid odd errors such: include/sysemu/xen.h:35:44: error: unknown type name 'ram_addr_t'; did you mean 'in_addr_t'? 35 | static inline void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length) | ^~~~~~~~~~ | in_addr_t Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200908155530.249806-4-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- include/sysemu/xen.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sysemu/xen.h b/include/sysemu/xen.h index 2c2c429ea8..0ca25697e4 100644 --- a/include/sysemu/xen.h +++ b/include/sysemu/xen.h @@ -8,6 +8,8 @@ #ifndef SYSEMU_XEN_H #define SYSEMU_XEN_H +#include "exec/cpu-common.h" + #ifdef NEED_CPU_H # ifdef CONFIG_XEN # define CONFIG_XEN_IS_POSSIBLE From 71f364b703119a319e6ac423c9446849d010abf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Sep 2020 17:55:28 +0200 Subject: [PATCH 71/86] stubs: Split accelerator / hardware related stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move hardware stubs unrelated from the accelerator to xen-hw-stub.c. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200908155530.249806-5-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + accel/stubs/xen-stub.c | 41 +---------------------------------- stubs/meson.build | 1 + stubs/xen-hw-stub.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 40 deletions(-) create mode 100644 stubs/xen-hw-stub.c diff --git a/MAINTAINERS b/MAINTAINERS index 2c8366d3a5..ffcf222243 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -480,6 +480,7 @@ F: include/hw/block/dataplane/xen* F: include/hw/xen/ F: include/sysemu/xen.h F: include/sysemu/xen-mapcache.h +F: stubs/xen-hw-stub.c Guest CPU Cores (HAXM) --------------------- diff --git a/accel/stubs/xen-stub.c b/accel/stubs/xen-stub.c index fa3dddbce5..7ba0b697f4 100644 --- a/accel/stubs/xen-stub.c +++ b/accel/stubs/xen-stub.c @@ -6,50 +6,11 @@ */ #include "qemu/osdep.h" -#include "hw/xen/xen.h" +#include "sysemu/xen.h" #include "qapi/qapi-commands-misc.h" bool xen_allowed; -void xenstore_store_pv_console_info(int i, Chardev *chr) -{ -} - -int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -{ - return -1; -} - -void xen_piix3_set_irq(void *opaque, int irq_num, int level) -{ -} - -void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) -{ -} - -void xen_hvm_inject_msi(uint64_t addr, uint32_t data) -{ -} - -int xen_is_pirq_msi(uint32_t msi_data) -{ - return 0; -} - -qemu_irq *xen_interrupt_controller_init(void) -{ - return NULL; -} - -void xen_register_framebuffer(MemoryRegion *mr) -{ -} - -void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory) -{ -} - void qmp_xen_set_global_dirty_log(bool enable, Error **errp) { } diff --git a/stubs/meson.build b/stubs/meson.build index e0b322bc28..5730f1d967 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -46,4 +46,5 @@ stub_ss.add(files('vm-stop.c')) stub_ss.add(files('win32-kbd-hook.c')) if have_system stub_ss.add(files('semihost.c')) + stub_ss.add(files('xen-hw-stub.c')) endif diff --git a/stubs/xen-hw-stub.c b/stubs/xen-hw-stub.c new file mode 100644 index 0000000000..d14efef49e --- /dev/null +++ b/stubs/xen-hw-stub.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 Citrix Systems UK Ltd. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/xen/xen.h" + +void xenstore_store_pv_console_info(int i, Chardev *chr) +{ +} + +int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + return -1; +} + +void xen_piix3_set_irq(void *opaque, int irq_num, int level) +{ +} + +void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) +{ +} + +void xen_hvm_inject_msi(uint64_t addr, uint32_t data) +{ +} + +int xen_is_pirq_msi(uint32_t msi_data) +{ + return 0; +} + +qemu_irq *xen_interrupt_controller_init(void) +{ + return NULL; +} + +void xen_register_framebuffer(MemoryRegion *mr) +{ +} + +void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory) +{ +} From c834596f7916c3ec0719c1ab341186bae17ebba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Sep 2020 17:55:29 +0200 Subject: [PATCH 72/86] hw/xen: Split x86-specific declaration from generic hardware ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xen_hvm_init() is restricted to the X86 architecture. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200908155530.249806-6-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc_piix.c | 2 +- hw/i386/xen/xen-hvm.c | 1 + include/hw/xen/xen-x86.h | 15 +++++++++++++++ include/hw/xen/xen.h | 2 -- stubs/xen-hw-stub.c | 1 + 5 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 include/hw/xen/xen-x86.h diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 9eaf8d6e0d..7d5aa6d1ba 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -46,7 +46,7 @@ #include "hw/sysbus.h" #include "sysemu/arch_init.h" #include "hw/i2c/smbus_eeprom.h" -#include "hw/xen/xen.h" +#include "hw/xen/xen-x86.h" #include "exec/memory.h" #include "exec/address-spaces.h" #include "hw/acpi/acpi.h" diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 91b6a30061..f3ababf33b 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -22,6 +22,7 @@ #include "hw/xen/xen_common.h" #include "hw/xen/xen-legacy-backend.h" #include "hw/xen/xen-bus.h" +#include "hw/xen/xen-x86.h" #include "qapi/error.h" #include "qapi/qapi-commands-misc.h" #include "qemu/error-report.h" diff --git a/include/hw/xen/xen-x86.h b/include/hw/xen/xen-x86.h new file mode 100644 index 0000000000..85e3db1b8d --- /dev/null +++ b/include/hw/xen/xen-x86.h @@ -0,0 +1,15 @@ +/* + * Xen X86-specific + * + * Copyright 2020 Red Hat, Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef QEMU_HW_XEN_X86_H +#define QEMU_HW_XEN_X86_H + +#include "hw/i386/pc.h" + +void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory); + +#endif /* QEMU_HW_XEN_X86_H */ diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index b2b459964c..1406648ca5 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -30,8 +30,6 @@ qemu_irq *xen_interrupt_controller_init(void); void xenstore_store_pv_console_info(int i, struct Chardev *chr); -void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory); - void xen_register_framebuffer(struct MemoryRegion *mr); #endif /* QEMU_HW_XEN_H */ diff --git a/stubs/xen-hw-stub.c b/stubs/xen-hw-stub.c index d14efef49e..2ea8190921 100644 --- a/stubs/xen-hw-stub.c +++ b/stubs/xen-hw-stub.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "hw/xen/xen.h" +#include "hw/xen/xen-x86.h" void xenstore_store_pv_console_info(int i, Chardev *chr) { From c8ed1cd7843c17a264dd578b3220c6398904858a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 8 Sep 2020 17:55:30 +0200 Subject: [PATCH 73/86] typedefs: Restrict PCMachineState to 'hw/i386/pc.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCMachineState type is only used under hw/i386/. We don't need to forward-declare it for all architectures, restrict it to the X86 one. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200908155530.249806-7-philmd@redhat.com> Signed-off-by: Paolo Bonzini --- include/hw/i386/pc.h | 4 ++-- include/qemu/typedefs.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c71b02cafd..8699029053 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -20,7 +20,7 @@ * @boot_cpus: number of present VCPUs * @smp_dies: number of dies per one package */ -struct PCMachineState { +typedef struct PCMachineState { /*< private >*/ X86MachineState parent_obj; @@ -50,7 +50,7 @@ struct PCMachineState { /* ACPI Memory hotplug IO base address */ hwaddr memhp_io_base; -}; +} PCMachineState; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" #define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g" diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 427027a970..6281eae3b5 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -90,7 +90,6 @@ typedef struct PCIExpressDevice PCIExpressDevice; typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIHostDeviceAddress PCIHostDeviceAddress; typedef struct PCIHostState PCIHostState; -typedef struct PCMachineState PCMachineState; typedef struct PostcopyDiscardState PostcopyDiscardState; typedef struct Property Property; typedef struct PropertyInfo PropertyInfo; From bfac6d1933a5fd8198e622dfd19196c2cc6cf74b Mon Sep 17 00:00:00 2001 From: Dov Murik Date: Mon, 14 Sep 2020 17:26:23 +0000 Subject: [PATCH 74/86] checkpatch: Detect '%#' or '%0#' in printf-style format strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the coding style document, we should use literal '0x' prefix instead of printf's '#' flag (which appears as '%#' or '%0#' in the format string). Add a checkpatch rule to enforce that. Note that checkpatch already had a similar rule for trace-events files. Example usage: $ scripts/checkpatch.pl --file chardev/baum.c ... ERROR: Don't use '#' flag of printf format ('%#') in format strings, use '0x' prefix instead #366: FILE: chardev/baum.c:366: + DPRINTF("Broken packet %#2x, tossing\n", req); \ ... ERROR: Don't use '#' flag of printf format ('%#') in format strings, use '0x' prefix instead #472: FILE: chardev/baum.c:472: + DPRINTF("unrecognized request %0#2x\n", req); ... Signed-off-by: Dov Murik Message-Id: <20200914172623.72955-1-dovmurik@linux.vnet.ibm.com> Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé --- scripts/checkpatch.pl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ca4445ffe9..6ed34970f9 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2880,14 +2880,20 @@ sub process { $herecurr); } -# check for %L{u,d,i} in strings +# format strings checks my $string; while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { $string = substr($rawline, $-[1], $+[1] - $-[1]); $string =~ s/%%/__/g; + # check for %L{u,d,i} in strings if ($string =~ /(? Date: Tue, 22 Sep 2020 14:17:56 +1000 Subject: [PATCH 75/86] helper_syscall x86_64: clear exception_is_int The exception_is_int flag may be set on entry to helper_syscall, e.g. after a prior interrupt that has returned, and processing EXCP_SYSCALL as an interrupt causes it to fail so clear this flag. Signed-off-by: Douglas Crosher Message-Id: Signed-off-by: Paolo Bonzini --- target/i386/seg_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/seg_helper.c b/target/i386/seg_helper.c index b96de068ca..be88938c2a 100644 --- a/target/i386/seg_helper.c +++ b/target/i386/seg_helper.c @@ -975,6 +975,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) CPUState *cs = env_cpu(env); cs->exception_index = EXCP_SYSCALL; + env->exception_is_int = 0; env->exception_next_eip = env->eip + next_eip_addend; cpu_loop_exit(cs); } From 6615be072dbb88d306cd1647c7c7b694682bac5e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 17 Sep 2020 12:23:16 +0200 Subject: [PATCH 76/86] target/i386: Fix VM migration when interrupt based APF is enabled VM with interrupt based APF enabled fails to migrate: qemu-system-x86_64: error: failed to set MSR 0x4b564d02 to 0xf3 We have two issues: 1) There is a typo in kvm_put_msrs() and we write async_pf_int_msr to MSR_KVM_ASYNC_PF_EN (instead of MSR_KVM_ASYNC_PF_INT) 2) We restore MSR_KVM_ASYNC_PF_EN before MSR_KVM_ASYNC_PF_INT is set and this violates the check in KVM. Re-order MSR_KVM_ASYNC_PF_EN/MSR_KVM_ASYNC_PF_INT setting (and kvm_get_msrs() for consistency) and fix the typo. Signed-off-by: Vitaly Kuznetsov Message-Id: <20200917102316.814804-1-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- target/i386/kvm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 06c2025c67..b327e8706f 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -2819,12 +2819,12 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, MSR_IA32_TSC, env->tsc); kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, env->system_time_msr); kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, env->wall_clock_msr); + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) { + kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_INT, env->async_pf_int_msr); + } if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) { kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr); } - if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) { - kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, env->async_pf_int_msr); - } if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) { kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, env->pv_eoi_en_msr); } @@ -3207,12 +3207,12 @@ static int kvm_get_msrs(X86CPU *cpu) #endif kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, 0); kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, 0); - if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) { - kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, 0); - } if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) { kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_INT, 0); } + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) { + kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, 0); + } if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) { kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, 0); } From 8700a984436e561e29903731d7db11a4b61acd76 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 22 Sep 2020 17:19:34 +0200 Subject: [PATCH 77/86] target/i386: always create kvmclock device QEMU's kvmclock device is only created when KVM PV feature bits for kvmclock (KVM_FEATURE_CLOCKSOURCE/KVM_FEATURE_CLOCKSOURCE2) are exposed to the guest. With 'kvm=off' cpu flag the device is not created and we don't call KVM_GET_CLOCK/KVM_SET_CLOCK upon migration. It was reported that without these call at least Hyper-V TSC page clocksouce (which can be enabled independently) gets broken after migration. Switch to creating kvmclock QEMU device unconditionally, it seems to always make sense to call KVM_GET_CLOCK/KVM_SET_CLOCK on migration. Use KVM_CAP_ADJUST_CLOCK check instead of CPUID feature bits. Reported-by: Antoine Damhet Suggested-by: Paolo Bonzini Signed-off-by: Vitaly Kuznetsov Message-Id: <20200922151934.899555-1-vkuznets@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i386/kvm/clock.c | 7 +++++-- hw/i386/microvm.c | 2 +- hw/i386/pc.c | 1 + hw/i386/pc_piix.c | 7 +++++-- hw/i386/pc_q35.c | 5 ++++- include/hw/i386/pc.h | 3 +++ include/hw/kvm/clock.h | 4 ++-- target/i386/kvm.c | 5 +++++ target/i386/kvm_i386.h | 1 + 9 files changed, 27 insertions(+), 8 deletions(-) diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 7b296ae192..24fe5091b6 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -329,11 +329,14 @@ static const TypeInfo kvmclock_info = { }; /* Note: Must be called after VCPU initialization. */ -void kvmclock_create(void) +void kvmclock_create(bool create_always) { X86CPU *cpu = X86_CPU(first_cpu); - if (kvm_enabled() && + if (!kvm_enabled() || !kvm_has_adjust_clock()) + return; + + if (create_always || cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) | (1ULL << KVM_FEATURE_CLOCKSOURCE2))) { sysbus_create_simple(TYPE_KVM_CLOCK, -1, NULL); diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 60d3272230..aedcae3426 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -125,7 +125,7 @@ static void microvm_devices_init(MicrovmMachineState *mms) ioapic_init_gsi(gsi_state, "machine"); - kvmclock_create(); + kvmclock_create(true); mms->virtio_irq_base = x86_machine_is_acpi_enabled(x86ms) ? 16 : 5; for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) { diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2c6194e57f..e87be5d29a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1657,6 +1657,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) pcmc->acpi_data_size = 0x20000 + 0x8000; pcmc->linuxboot_dma_enabled = true; pcmc->pvh_enabled = true; + pcmc->kvmclock_create_always = true; assert(!mc->get_hotplug_handler); mc->get_hotplug_handler = pc_get_hotplug_handler; mc->hotplug_allowed = pc_hotplug_allowed; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 7d5aa6d1ba..3c2ae0612b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -158,8 +158,8 @@ static void pc_init1(MachineState *machine, x86_cpus_init(x86ms, pcmc->default_cpu_version); - if (kvm_enabled() && pcmc->kvmclock_enabled) { - kvmclock_create(); + if (pcmc->kvmclock_enabled) { + kvmclock_create(pcmc->kvmclock_create_always); } if (pcmc->pci_enabled) { @@ -440,11 +440,14 @@ DEFINE_I440FX_MACHINE(v5_2, "pc-i440fx-5.2", NULL, static void pc_i440fx_5_1_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_i440fx_5_2_machine_options(m); m->alias = NULL; m->is_default = false; compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len); compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len); + pcmc->kvmclock_create_always = false; } DEFINE_I440FX_MACHINE(v5_1, "pc-i440fx-5.1", NULL, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 491ab53d74..a3f4959c43 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -179,7 +179,7 @@ static void pc_q35_init(MachineState *machine) x86_cpus_init(x86ms, pcmc->default_cpu_version); - kvmclock_create(); + kvmclock_create(pcmc->kvmclock_create_always); /* pci enabled */ if (pcmc->pci_enabled) { @@ -357,10 +357,13 @@ DEFINE_Q35_MACHINE(v5_2, "pc-q35-5.2", NULL, static void pc_q35_5_1_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_q35_5_2_machine_options(m); m->alias = NULL; compat_props_add(m->compat_props, hw_compat_5_1, hw_compat_5_1_len); compat_props_add(m->compat_props, pc_compat_5_1, pc_compat_5_1_len); + pcmc->kvmclock_create_always = false; } DEFINE_Q35_MACHINE(v5_1, "pc-q35-5.1", NULL, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 8699029053..84639d0ebc 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -118,6 +118,9 @@ struct PCMachineClass { /* use PVH to load kernels that support this feature */ bool pvh_enabled; + + /* create kvmclock device even when KVM PV features are not exposed */ + bool kvmclock_create_always; }; #define TYPE_PC_MACHINE "generic-pc-machine" diff --git a/include/hw/kvm/clock.h b/include/hw/kvm/clock.h index 81c66b2302..7994071c4f 100644 --- a/include/hw/kvm/clock.h +++ b/include/hw/kvm/clock.h @@ -15,11 +15,11 @@ #ifdef CONFIG_KVM -void kvmclock_create(void); +void kvmclock_create(bool create_always); #else /* CONFIG_KVM */ -static inline void kvmclock_create(void) +static inline void kvmclock_create(bool create_always) { } diff --git a/target/i386/kvm.c b/target/i386/kvm.c index b327e8706f..4fc6e8b9d5 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -143,6 +143,11 @@ bool kvm_has_adjust_clock_stable(void) return (ret == KVM_CLOCK_TSC_STABLE); } +bool kvm_has_adjust_clock(void) +{ + return kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK); +} + bool kvm_has_exception_payload(void) { return has_exception_payload; diff --git a/target/i386/kvm_i386.h b/target/i386/kvm_i386.h index 064b8798a2..0fce4e51d2 100644 --- a/target/i386/kvm_i386.h +++ b/target/i386/kvm_i386.h @@ -34,6 +34,7 @@ bool kvm_allows_irq0_override(void); bool kvm_has_smm(void); +bool kvm_has_adjust_clock(void); bool kvm_has_adjust_clock_stable(void); bool kvm_has_exception_payload(void); void kvm_synchronize_all_tsc(void); From d1e2d46467b95b0327935db91241fed27a053af4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Sep 2020 15:47:32 -0400 Subject: [PATCH 78/86] bios-tables-test: Remove kernel-irqchip=off option We don't need to use kernel-irqchip=off for irq0 override if IRQ routing is supported by the host, which is the case since 2009 (IRQ routing was added to KVM in Linux v2.6.30). This is a more straightforward fix for Launchpad bug #1896263, as it doesn't require increasing the complexity of the MSR code. kernel-irqchip=off is for debugging only and there's no need to increase the complexity of the code just to work around an issue that was already fixed in the kernel. Fixes: https://bugs.launchpad.net/bugs/1896263 Signed-off-by: Eduardo Habkost Message-Id: <20200922194732.2100510-1-ehabkost@redhat.com> Signed-off-by: Paolo Bonzini --- tests/qtest/bios-tables-test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index b514b70b62..67d1bed082 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -663,8 +663,7 @@ static void test_acpi_one(const char *params, test_data *data) data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : ""); } else { - /* Disable kernel irqchip to be able to override apic irq0. */ - args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg " + args = g_strdup_printf("-machine %s %s -accel tcg " "-net none -display none %s " "-drive id=hd0,if=none,file=%s,format=raw " "-device %s,drive=hd0 ", From c3dfce9afd8437d22241d2f22fd126826a8e919f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Sep 2020 23:01:39 -0400 Subject: [PATCH 79/86] target/i386: kvm: do not use kvm_check_extension to find paravirtual capabilities Paravirtualized features have been listed in KVM_GET_SUPPORTED_CPUID since Linux 2.6.35 (commit 84478c829d0f, "KVM: x86: export paravirtual cpuid flags in KVM_GET_SUPPORTED_CPUID", 2010-05-19). It has been more than 10 years, so remove the fallback code. Signed-off-by: Paolo Bonzini --- target/i386/kvm.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 4fc6e8b9d5..f6dae4cfb6 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -284,30 +284,6 @@ static struct kvm_cpuid2 *get_supported_cpuid(KVMState *s) return cpuid; } -static const struct kvm_para_features { - int cap; - int feature; -} para_features[] = { - { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE }, - { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY }, - { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, - { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, - { KVM_CAP_ASYNC_PF_INT, KVM_FEATURE_ASYNC_PF_INT }, -}; - -static int get_para_features(KVMState *s) -{ - int i, features = 0; - - for (i = 0; i < ARRAY_SIZE(para_features); i++) { - if (kvm_check_extension(s, para_features[i].cap)) { - features |= (1 << para_features[i].feature); - } - } - - return features; -} - static bool host_tsx_broken(void) { int family, model, stepping;\ @@ -367,13 +343,11 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, struct kvm_cpuid2 *cpuid; uint32_t ret = 0; uint32_t cpuid_1_edx; - bool found = false; cpuid = get_supported_cpuid(s); struct kvm_cpuid_entry2 *entry = cpuid_find_entry(cpuid, function, index); if (entry) { - found = true; ret = cpuid_entry_get_reg(entry, reg); } @@ -448,12 +422,6 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, } } else if (function == KVM_CPUID_FEATURES && reg == R_EDX) { ret |= 1U << KVM_HINTS_REALTIME; - found = 1; - } - - /* fallback for older kernels */ - if ((function == KVM_CPUID_FEATURES) && !found) { - ret = get_para_features(s); } return ret; From d44948ccbd56cde7be989da5cc872b0c05bf6224 Mon Sep 17 00:00:00 2001 From: Jan Charvat Date: Mon, 14 Sep 2020 10:09:02 +0200 Subject: [PATCH 80/86] net/can: Initial host SocketCan support for CAN FD. Signed-off-by: Jan Charvat Signed-off-by: Pavel Pisa Reviewed-by: Vikram Garhwal Message-Id: <41383d4eb3f35586c696a8e29c4dff4031a81338.1600069689.git.pisa@cmp.felk.cvut.cz> Signed-off-by: Paolo Bonzini --- hw/net/can/can_sja1000.c | 2 ++ include/net/can_emu.h | 8 ++++++- net/can/can_socketcan.c | 47 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c index 299932998a..ec66d4232d 100644 --- a/hw/net/can/can_sja1000.c +++ b/hw/net/can/can_sja1000.c @@ -268,6 +268,7 @@ static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame) { uint8_t i; + frame->flags = 0; frame->can_id = 0; if (buff[0] & 0x40) { /* RTR */ frame->can_id = QEMU_CAN_RTR_FLAG; @@ -303,6 +304,7 @@ static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame) { uint8_t i; + frame->flags = 0; frame->can_id = ((buff[0] << 3) & (0xff << 3)) + ((buff[1] >> 5) & 0x07); if (buff[1] & 0x10) { /* RTR */ frame->can_id = QEMU_CAN_RTR_FLAG; diff --git a/include/net/can_emu.h b/include/net/can_emu.h index 743c6647c1..cab98ee8ec 100644 --- a/include/net/can_emu.h +++ b/include/net/can_emu.h @@ -46,7 +46,8 @@ typedef uint32_t qemu_canid_t; typedef struct qemu_can_frame { qemu_canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ uint8_t can_dlc; /* data length code: 0 .. 8 */ - uint8_t data[8] QEMU_ALIGNED(8); + uint8_t flags; + uint8_t data[64] QEMU_ALIGNED(8); } qemu_can_frame; /* Keep defines for QEMU separate from Linux ones for now */ @@ -58,6 +59,10 @@ typedef struct qemu_can_frame { #define QEMU_CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */ #define QEMU_CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */ +#define QEMU_CAN_FRMF_BRS 0x01 /* bit rate switch (2nd bitrate for data) */ +#define QEMU_CAN_FRMF_ESI 0x02 /* error state ind. of transmitting node */ +#define QEMU_CAN_FRMF_TYPE_FD 0x10 /* internal bit ind. of CAN FD frame */ + /** * struct qemu_can_filter - CAN ID based filter in can_register(). * @can_id: relevant bits of CAN ID which are not masked out. @@ -97,6 +102,7 @@ struct CanBusClientState { char *model; char *name; void (*destructor)(CanBusClientState *); + bool fd_mode; }; #define TYPE_CAN_BUS "can-bus" diff --git a/net/can/can_socketcan.c b/net/can/can_socketcan.c index ce8c2549ed..92b1f79385 100644 --- a/net/can/can_socketcan.c +++ b/net/can/can_socketcan.c @@ -103,6 +103,14 @@ static void can_host_socketcan_read(void *opaque) return; } + if (!ch->bus_client.fd_mode) { + c->buf[0].flags = 0; + } else { + if (c->bufcnt > CAN_MTU) { + c->buf[0].flags |= QEMU_CAN_FRMF_TYPE_FD; + } + } + can_bus_client_send(&ch->bus_client, c->buf, 1); if (DEBUG_CAN) { @@ -121,12 +129,21 @@ static ssize_t can_host_socketcan_receive(CanBusClientState *client, CanHostState *ch = container_of(client, CanHostState, bus_client); CanHostSocketCAN *c = CAN_HOST_SOCKETCAN(ch); - size_t len = sizeof(qemu_can_frame); + size_t len; int res; if (c->fd < 0) { return -1; } + if (frames->flags & QEMU_CAN_FRMF_TYPE_FD) { + if (!ch->bus_client.fd_mode) { + return 0; + } + len = CANFD_MTU; + } else { + len = CAN_MTU; + + } res = write(c->fd, frames, len); @@ -172,6 +189,8 @@ static void can_host_socketcan_connect(CanHostState *ch, Error **errp) { CanHostSocketCAN *c = CAN_HOST_SOCKETCAN(ch); int s; /* can raw socket */ + int mtu; + int enable_canfd = 1; struct sockaddr_can addr; struct ifreq ifr; @@ -185,13 +204,34 @@ static void can_host_socketcan_connect(CanHostState *ch, Error **errp) addr.can_family = AF_CAN; memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name)); strcpy(ifr.ifr_name, c->ifname); + /* check if the frame fits into the CAN netdevice */ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { error_setg_errno(errp, errno, - "SocketCAN host interface %s not available", c->ifname); + "SocketCAN host interface %s not available", + c->ifname); goto fail; } addr.can_ifindex = ifr.ifr_ifindex; + if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { + error_setg_errno(errp, errno, + "SocketCAN host interface %s SIOCGIFMTU failed", + c->ifname); + goto fail; + } + mtu = ifr.ifr_mtu; + + if (mtu >= CANFD_MTU) { + /* interface is ok - try to switch the socket into CAN FD mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enable_canfd, sizeof(enable_canfd))) { + warn_report("SocketCAN host interface %s enabling CAN FD failed", + c->ifname); + } else { + c->parent.bus_client.fd_mode = true; + } + } + c->err_mask = 0xffffffff; /* Receive error frame. */ setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &c->err_mask, sizeof(c->err_mask)); @@ -232,7 +272,8 @@ static char *can_host_socketcan_get_if(Object *obj, Error **errp) return g_strdup(c->ifname); } -static void can_host_socketcan_set_if(Object *obj, const char *value, Error **errp) +static void can_host_socketcan_set_if(Object *obj, const char *value, + Error **errp) { CanHostSocketCAN *c = CAN_HOST_SOCKETCAN(obj); struct ifreq ifr; From 46b25fe08b37ea87b7c576a37c27c608f4d7621e Mon Sep 17 00:00:00 2001 From: Jan Charvat Date: Mon, 14 Sep 2020 10:13:37 +0200 Subject: [PATCH 81/86] hw/net/can: sja1000 ignore CAN FD frames Signed-off-by: Jan Charvat Signed-off-by: Pavel Pisa Reviewed-by: Vikram Garhwal Message-Id: <48d9ebf6b64e7652851c12fe4566e06b44803372.1600069689.git.pisa@cmp.felk.cvut.cz> Signed-off-by: Paolo Bonzini --- hw/net/can/can_sja1000.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c index ec66d4232d..42d2f99dfb 100644 --- a/hw/net/can/can_sja1000.c +++ b/hw/net/can/can_sja1000.c @@ -323,11 +323,16 @@ static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame) static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff) { int i; + int dlen = frame->can_dlc; if (frame->can_id & QEMU_CAN_ERR_FLAG) { /* error frame, NOT support now. */ return -1; } + if (dlen > 8) { + return -1; + } + buff[0] = 0x0f & frame->can_dlc; /* DLC */ if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */ buff[0] |= (1 << 6); @@ -338,18 +343,18 @@ static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff) buff[2] = extract32(frame->can_id, 13, 8); /* ID.20~ID.13 */ buff[3] = extract32(frame->can_id, 5, 8); /* ID.12~ID.05 */ buff[4] = extract32(frame->can_id, 0, 5) << 3; /* ID.04~ID.00,xxx */ - for (i = 0; i < frame->can_dlc; i++) { + for (i = 0; i < dlen; i++) { buff[5 + i] = frame->data[i]; } - return frame->can_dlc + 5; + return dlen + 5; } else { /* SFF */ buff[1] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */ buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */ - for (i = 0; i < frame->can_dlc; i++) { + for (i = 0; i < dlen; i++) { buff[3 + i] = frame->data[i]; } - return frame->can_dlc + 3; + return dlen + 3; } return -1; @@ -358,6 +363,7 @@ static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff) static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff) { int i; + int dlen = frame->can_dlc; /* * EFF, no support for BasicMode @@ -369,17 +375,21 @@ static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff) return -1; } + if (dlen > 8) { + return -1; + } + buff[0] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */ buff[1] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */ if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */ buff[1] |= (1 << 4); } buff[1] |= frame->can_dlc & 0x0f; - for (i = 0; i < frame->can_dlc; i++) { + for (i = 0; i < dlen; i++) { buff[2 + i] = frame->data[i]; } - return frame->can_dlc + 2; + return dlen + 2; } static void can_sja_update_pel_irq(CanSJA1000State *s) @@ -766,6 +776,13 @@ ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames, if (frames_cnt <= 0) { return 0; } + if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) { + if (DEBUG_FILTER) { + can_display_msg("[cansja]: ignor fd frame ", frame); + } + return 1; + } + if (DEBUG_FILTER) { can_display_msg("[cansja]: receive ", frame); } From ad0c6740d1085a67f319ed1432598e3f3912a707 Mon Sep 17 00:00:00 2001 From: Jan Charvat Date: Mon, 14 Sep 2020 10:13:38 +0200 Subject: [PATCH 82/86] net/can: Add can_dlc2len and can_len2dlc for CAN FD. Signed-off-by: Jan Charvat Signed-off-by: Pavel Pisa Reviewed-by: Vikram Garhwal Message-Id: <0a2efc6ef9c458505952ed230e49ae25cad7f324.1600069689.git.pisa@cmp.felk.cvut.cz> Signed-off-by: Paolo Bonzini --- include/net/can_emu.h | 4 ++++ net/can/can_core.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/net/can_emu.h b/include/net/can_emu.h index cab98ee8ec..6f9b206bb5 100644 --- a/include/net/can_emu.h +++ b/include/net/can_emu.h @@ -122,4 +122,8 @@ int can_bus_client_set_filters(CanBusClientState *, const struct qemu_can_filter *filters, size_t filters_cnt); +uint8_t can_dlc2len(uint8_t can_dlc); + +uint8_t can_len2dlc(uint8_t len); + #endif diff --git a/net/can/can_core.c b/net/can/can_core.c index 90f4d8576a..0115d78794 100644 --- a/net/can/can_core.c +++ b/net/can/can_core.c @@ -33,6 +33,42 @@ #include "net/can_emu.h" #include "qom/object_interfaces.h" +/* CAN DLC to real data length conversion helpers */ + +static const uint8_t dlc2len[] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 12, 16, 20, 24, 32, 48, 64 +}; + +/* get data length from can_dlc with sanitized can_dlc */ +uint8_t can_dlc2len(uint8_t can_dlc) +{ + return dlc2len[can_dlc & 0x0F]; +} + +static const uint8_t len2dlc[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ + 9, 9, 9, 9, /* 9 - 12 */ + 10, 10, 10, 10, /* 13 - 16 */ + 11, 11, 11, 11, /* 17 - 20 */ + 12, 12, 12, 12, /* 21 - 24 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */ + 15, 15, 15, 15, 15, 15, 15, 15 /* 57 - 64 */ +}; + +/* map the sanitized data length to an appropriate data length code */ +uint8_t can_len2dlc(uint8_t len) +{ + if (unlikely(len > 64)) { + return 0xF; + } + + return len2dlc[len]; +} + struct CanBusState { Object object; From 3c21c530a3ddd37bc194a68e2da7ef70672cc591 Mon Sep 17 00:00:00 2001 From: Jan Charvat Date: Mon, 14 Sep 2020 10:13:39 +0200 Subject: [PATCH 83/86] hw/net/can/ctucafd: Add CTU CAN FD core register definitions. Definitions of registers and CAN FD frame message box of CTU CAN FD IP core are generated the specification in CACTUS/IP-XACT format. CTU CAN FD IP core repository https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core The location of the CTU CAN IP core specification within IP core design spec/CTU/ip/CAN_FD_IP_Core/2.1/CAN_FD_IP_Core.2.1.xml The header files are generated by pyXact_generator designed by Ondrej Ille which is based on ipyxact_parser. The specification is source of header files for driver and emulation, documentation and VHDL registers map implementation. Signed-off-by: Jan Charvat Signed-off-by: Pavel Pisa Message-Id: <97ae620f724bf1d76f127aaf628f7aec3af0a11c.1600069689.git.pisa@cmp.felk.cvut.cz> Signed-off-by: Paolo Bonzini --- hw/net/can/ctu_can_fd_frame.h | 189 +++++++ hw/net/can/ctu_can_fd_regs.h | 971 ++++++++++++++++++++++++++++++++++ 2 files changed, 1160 insertions(+) create mode 100644 hw/net/can/ctu_can_fd_frame.h create mode 100644 hw/net/can/ctu_can_fd_regs.h diff --git a/hw/net/can/ctu_can_fd_frame.h b/hw/net/can/ctu_can_fd_frame.h new file mode 100644 index 0000000000..04d956c84e --- /dev/null +++ b/hw/net/can/ctu_can_fd_frame.h @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille FEE CTU + * Copyright (C) 2018-2020 Ondrej Ille self-funded + * Copyright (C) 2018-2019 Martin Jerabek FEE CTU + * Copyright (C) 2018-2020 Pavel Pisa FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak + * Pavel Pisa + * + * Department of Measurement (http://meas.fel.cvut.cz/) + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + ******************************************************************************/ + +/* This file is autogenerated, DO NOT EDIT! */ + +#ifndef __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ +#define __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__ + +/* CAN_Frame_format memory map */ +enum ctu_can_fd_can_frame_format { + CTU_CAN_FD_FRAME_FORM_W = 0x0, + CTU_CAN_FD_IDENTIFIER_W = 0x4, + CTU_CAN_FD_TIMESTAMP_L_W = 0x8, + CTU_CAN_FD_TIMESTAMP_U_W = 0xc, + CTU_CAN_FD_DATA_1_4_W = 0x10, + CTU_CAN_FD_DATA_5_8_W = 0x14, + CTU_CAN_FD_DATA_61_64_W = 0x4c, +}; + + +/* Register descriptions: */ +union ctu_can_fd_frame_form_w { + uint32_t u32; + struct ctu_can_fd_frame_form_w_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FRAME_FORM_W */ + uint32_t dlc : 4; + uint32_t reserved_4 : 1; + uint32_t rtr : 1; + uint32_t ide : 1; + uint32_t fdf : 1; + uint32_t reserved_8 : 1; + uint32_t brs : 1; + uint32_t esi_rsv : 1; + uint32_t rwcnt : 5; + uint32_t reserved_31_16 : 16; +#else + uint32_t reserved_31_16 : 16; + uint32_t rwcnt : 5; + uint32_t esi_rsv : 1; + uint32_t brs : 1; + uint32_t reserved_8 : 1; + uint32_t fdf : 1; + uint32_t ide : 1; + uint32_t rtr : 1; + uint32_t reserved_4 : 1; + uint32_t dlc : 4; +#endif + } s; +}; + +enum ctu_can_fd_frame_form_w_rtr { + NO_RTR_FRAME = 0x0, + RTR_FRAME = 0x1, +}; + +enum ctu_can_fd_frame_form_w_ide { + BASE = 0x0, + EXTENDED = 0x1, +}; + +enum ctu_can_fd_frame_form_w_fdf { + NORMAL_CAN = 0x0, + FD_CAN = 0x1, +}; + +enum ctu_can_fd_frame_form_w_brs { + BR_NO_SHIFT = 0x0, + BR_SHIFT = 0x1, +}; + +enum ctu_can_fd_frame_form_w_esi_rsv { + ESI_ERR_ACTIVE = 0x0, + ESI_ERR_PASIVE = 0x1, +}; + +union ctu_can_fd_identifier_w { + uint32_t u32; + struct ctu_can_fd_identifier_w_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* IDENTIFIER_W */ + uint32_t identifier_ext : 18; + uint32_t identifier_base : 11; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t identifier_base : 11; + uint32_t identifier_ext : 18; +#endif + } s; +}; + +union ctu_can_fd_timestamp_l_w { + uint32_t u32; + struct ctu_can_fd_timestamp_l_w_s { + /* TIMESTAMP_L_W */ + uint32_t time_stamp_31_0 : 32; + } s; +}; + +union ctu_can_fd_timestamp_u_w { + uint32_t u32; + struct ctu_can_fd_timestamp_u_w_s { + /* TIMESTAMP_U_W */ + uint32_t timestamp_l_w : 32; + } s; +}; + +union ctu_can_fd_data_1_4_w { + uint32_t u32; + struct ctu_can_fd_data_1_4_w_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* DATA_1_4_W */ + uint32_t data_1 : 8; + uint32_t data_2 : 8; + uint32_t data_3 : 8; + uint32_t data_4 : 8; +#else + uint32_t data_4 : 8; + uint32_t data_3 : 8; + uint32_t data_2 : 8; + uint32_t data_1 : 8; +#endif + } s; +}; + +union ctu_can_fd_data_5_8_w { + uint32_t u32; + struct ctu_can_fd_data_5_8_w_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* DATA_5_8_W */ + uint32_t data_5 : 8; + uint32_t data_6 : 8; + uint32_t data_7 : 8; + uint32_t data_8 : 8; +#else + uint32_t data_8 : 8; + uint32_t data_7 : 8; + uint32_t data_6 : 8; + uint32_t data_5 : 8; +#endif + } s; +}; + +union ctu_can_fd_data_61_64_w { + uint32_t u32; + struct ctu_can_fd_data_61_64_w_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* DATA_61_64_W */ + uint32_t data_61 : 8; + uint32_t data_62 : 8; + uint32_t data_63 : 8; + uint32_t data_64 : 8; +#else + uint32_t data_64 : 8; + uint32_t data_63 : 8; + uint32_t data_62 : 8; + uint32_t data_61 : 8; +#endif + } s; +}; + +#endif diff --git a/hw/net/can/ctu_can_fd_regs.h b/hw/net/can/ctu_can_fd_regs.h new file mode 100644 index 0000000000..450f4b9fb3 --- /dev/null +++ b/hw/net/can/ctu_can_fd_regs.h @@ -0,0 +1,971 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/******************************************************************************* + * + * CTU CAN FD IP Core + * + * Copyright (C) 2015-2018 Ondrej Ille FEE CTU + * Copyright (C) 2018-2020 Ondrej Ille self-funded + * Copyright (C) 2018-2019 Martin Jerabek FEE CTU + * Copyright (C) 2018-2020 Pavel Pisa FEE CTU/self-funded + * + * Project advisors: + * Jiri Novak + * Pavel Pisa + * + * Department of Measurement (http://meas.fel.cvut.cz/) + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + ******************************************************************************/ + +/* This file is autogenerated, DO NOT EDIT! */ + +#ifndef __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ +#define __CTU_CAN_FD_CAN_FD_REGISTER_MAP__ + +/* CAN_Registers memory map */ +enum ctu_can_fd_can_registers { + CTU_CAN_FD_DEVICE_ID = 0x0, + CTU_CAN_FD_VERSION = 0x2, + CTU_CAN_FD_MODE = 0x4, + CTU_CAN_FD_SETTINGS = 0x6, + CTU_CAN_FD_STATUS = 0x8, + CTU_CAN_FD_COMMAND = 0xc, + CTU_CAN_FD_INT_STAT = 0x10, + CTU_CAN_FD_INT_ENA_SET = 0x14, + CTU_CAN_FD_INT_ENA_CLR = 0x18, + CTU_CAN_FD_INT_MASK_SET = 0x1c, + CTU_CAN_FD_INT_MASK_CLR = 0x20, + CTU_CAN_FD_BTR = 0x24, + CTU_CAN_FD_BTR_FD = 0x28, + CTU_CAN_FD_EWL = 0x2c, + CTU_CAN_FD_ERP = 0x2d, + CTU_CAN_FD_FAULT_STATE = 0x2e, + CTU_CAN_FD_REC = 0x30, + CTU_CAN_FD_TEC = 0x32, + CTU_CAN_FD_ERR_NORM = 0x34, + CTU_CAN_FD_ERR_FD = 0x36, + CTU_CAN_FD_CTR_PRES = 0x38, + CTU_CAN_FD_FILTER_A_MASK = 0x3c, + CTU_CAN_FD_FILTER_A_VAL = 0x40, + CTU_CAN_FD_FILTER_B_MASK = 0x44, + CTU_CAN_FD_FILTER_B_VAL = 0x48, + CTU_CAN_FD_FILTER_C_MASK = 0x4c, + CTU_CAN_FD_FILTER_C_VAL = 0x50, + CTU_CAN_FD_FILTER_RAN_LOW = 0x54, + CTU_CAN_FD_FILTER_RAN_HIGH = 0x58, + CTU_CAN_FD_FILTER_CONTROL = 0x5c, + CTU_CAN_FD_FILTER_STATUS = 0x5e, + CTU_CAN_FD_RX_MEM_INFO = 0x60, + CTU_CAN_FD_RX_POINTERS = 0x64, + CTU_CAN_FD_RX_STATUS = 0x68, + CTU_CAN_FD_RX_SETTINGS = 0x6a, + CTU_CAN_FD_RX_DATA = 0x6c, + CTU_CAN_FD_TX_STATUS = 0x70, + CTU_CAN_FD_TX_COMMAND = 0x74, + CTU_CAN_FD_TX_PRIORITY = 0x78, + CTU_CAN_FD_ERR_CAPT = 0x7c, + CTU_CAN_FD_ALC = 0x7e, + CTU_CAN_FD_TRV_DELAY = 0x80, + CTU_CAN_FD_SSP_CFG = 0x82, + CTU_CAN_FD_RX_FR_CTR = 0x84, + CTU_CAN_FD_TX_FR_CTR = 0x88, + CTU_CAN_FD_DEBUG_REGISTER = 0x8c, + CTU_CAN_FD_YOLO_REG = 0x90, + CTU_CAN_FD_TIMESTAMP_LOW = 0x94, + CTU_CAN_FD_TIMESTAMP_HIGH = 0x98, + CTU_CAN_FD_TXTB1_DATA_1 = 0x100, + CTU_CAN_FD_TXTB1_DATA_2 = 0x104, + CTU_CAN_FD_TXTB1_DATA_20 = 0x14c, + CTU_CAN_FD_TXTB2_DATA_1 = 0x200, + CTU_CAN_FD_TXTB2_DATA_2 = 0x204, + CTU_CAN_FD_TXTB2_DATA_20 = 0x24c, + CTU_CAN_FD_TXTB3_DATA_1 = 0x300, + CTU_CAN_FD_TXTB3_DATA_2 = 0x304, + CTU_CAN_FD_TXTB3_DATA_20 = 0x34c, + CTU_CAN_FD_TXTB4_DATA_1 = 0x400, + CTU_CAN_FD_TXTB4_DATA_2 = 0x404, + CTU_CAN_FD_TXTB4_DATA_20 = 0x44c, +}; + + +/* Register descriptions: */ +union ctu_can_fd_device_id_version { + uint32_t u32; + struct ctu_can_fd_device_id_version_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* DEVICE_ID */ + uint32_t device_id : 16; + /* VERSION */ + uint32_t ver_minor : 8; + uint32_t ver_major : 8; +#else + uint32_t ver_major : 8; + uint32_t ver_minor : 8; + uint32_t device_id : 16; +#endif + } s; +}; + +enum ctu_can_fd_device_id_device_id { + CTU_CAN_FD_ID = 0xcafd, +}; + +union ctu_can_fd_mode_settings { + uint32_t u32; + struct ctu_can_fd_mode_settings_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* MODE */ + uint32_t rst : 1; + uint32_t lom : 1; + uint32_t stm : 1; + uint32_t afm : 1; + uint32_t fde : 1; + uint32_t reserved_6_5 : 2; + uint32_t acf : 1; + uint32_t tstm : 1; + uint32_t reserved_15_9 : 7; + /* SETTINGS */ + uint32_t rtrle : 1; + uint32_t rtrth : 4; + uint32_t ilbp : 1; + uint32_t ena : 1; + uint32_t nisofd : 1; + uint32_t pex : 1; + uint32_t reserved_31_25 : 7; +#else + uint32_t reserved_31_25 : 7; + uint32_t pex : 1; + uint32_t nisofd : 1; + uint32_t ena : 1; + uint32_t ilbp : 1; + uint32_t rtrth : 4; + uint32_t rtrle : 1; + uint32_t reserved_15_9 : 7; + uint32_t tstm : 1; + uint32_t acf : 1; + uint32_t reserved_6_5 : 2; + uint32_t fde : 1; + uint32_t afm : 1; + uint32_t stm : 1; + uint32_t lom : 1; + uint32_t rst : 1; +#endif + } s; +}; + +enum ctu_can_fd_mode_lom { + LOM_DISABLED = 0x0, + LOM_ENABLED = 0x1, +}; + +enum ctu_can_fd_mode_stm { + STM_DISABLED = 0x0, + STM_ENABLED = 0x1, +}; + +enum ctu_can_fd_mode_afm { + AFM_DISABLED = 0x0, + AFM_ENABLED = 0x1, +}; + +enum ctu_can_fd_mode_fde { + FDE_DISABLE = 0x0, + FDE_ENABLE = 0x1, +}; + +enum ctu_can_fd_mode_acf { + ACF_DISABLED = 0x0, + ACF_ENABLED = 0x1, +}; + +enum ctu_can_fd_settings_rtrle { + RTRLE_DISABLED = 0x0, + RTRLE_ENABLED = 0x1, +}; + +enum ctu_can_fd_settings_ilbp { + INT_LOOP_DISABLED = 0x0, + INT_LOOP_ENABLED = 0x1, +}; + +enum ctu_can_fd_settings_ena { + CTU_CAN_DISABLED = 0x0, + CTU_CAN_ENABLED = 0x1, +}; + +enum ctu_can_fd_settings_nisofd { + ISO_FD = 0x0, + NON_ISO_FD = 0x1, +}; + +enum ctu_can_fd_settings_pex { + PROTOCOL_EXCEPTION_DISABLED = 0x0, + PROTOCOL_EXCEPTION_ENABLED = 0x1, +}; + +union ctu_can_fd_status { + uint32_t u32; + struct ctu_can_fd_status_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* STATUS */ + uint32_t rxne : 1; + uint32_t dor : 1; + uint32_t txnf : 1; + uint32_t eft : 1; + uint32_t rxs : 1; + uint32_t txs : 1; + uint32_t ewl : 1; + uint32_t idle : 1; + uint32_t reserved_31_8 : 24; +#else + uint32_t reserved_31_8 : 24; + uint32_t idle : 1; + uint32_t ewl : 1; + uint32_t txs : 1; + uint32_t rxs : 1; + uint32_t eft : 1; + uint32_t txnf : 1; + uint32_t dor : 1; + uint32_t rxne : 1; +#endif + } s; +}; + +union ctu_can_fd_command { + uint32_t u32; + struct ctu_can_fd_command_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + uint32_t reserved_1_0 : 2; + /* COMMAND */ + uint32_t rrb : 1; + uint32_t cdo : 1; + uint32_t ercrst : 1; + uint32_t rxfcrst : 1; + uint32_t txfcrst : 1; + uint32_t reserved_31_7 : 25; +#else + uint32_t reserved_31_7 : 25; + uint32_t txfcrst : 1; + uint32_t rxfcrst : 1; + uint32_t ercrst : 1; + uint32_t cdo : 1; + uint32_t rrb : 1; + uint32_t reserved_1_0 : 2; +#endif + } s; +}; + +union ctu_can_fd_int_stat { + uint32_t u32; + struct ctu_can_fd_int_stat_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* INT_STAT */ + uint32_t rxi : 1; + uint32_t txi : 1; + uint32_t ewli : 1; + uint32_t doi : 1; + uint32_t fcsi : 1; + uint32_t ali : 1; + uint32_t bei : 1; + uint32_t ofi : 1; + uint32_t rxfi : 1; + uint32_t bsi : 1; + uint32_t rbnei : 1; + uint32_t txbhci : 1; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t txbhci : 1; + uint32_t rbnei : 1; + uint32_t bsi : 1; + uint32_t rxfi : 1; + uint32_t ofi : 1; + uint32_t bei : 1; + uint32_t ali : 1; + uint32_t fcsi : 1; + uint32_t doi : 1; + uint32_t ewli : 1; + uint32_t txi : 1; + uint32_t rxi : 1; +#endif + } s; +}; + +union ctu_can_fd_int_ena_set { + uint32_t u32; + struct ctu_can_fd_int_ena_set_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* INT_ENA_SET */ + uint32_t int_ena_set : 12; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t int_ena_set : 12; +#endif + } s; +}; + +union ctu_can_fd_int_ena_clr { + uint32_t u32; + struct ctu_can_fd_int_ena_clr_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* INT_ENA_CLR */ + uint32_t int_ena_clr : 12; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t int_ena_clr : 12; +#endif + } s; +}; + +union ctu_can_fd_int_mask_set { + uint32_t u32; + struct ctu_can_fd_int_mask_set_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* INT_MASK_SET */ + uint32_t int_mask_set : 12; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t int_mask_set : 12; +#endif + } s; +}; + +union ctu_can_fd_int_mask_clr { + uint32_t u32; + struct ctu_can_fd_int_mask_clr_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* INT_MASK_CLR */ + uint32_t int_mask_clr : 12; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t int_mask_clr : 12; +#endif + } s; +}; + +union ctu_can_fd_btr { + uint32_t u32; + struct ctu_can_fd_btr_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* BTR */ + uint32_t prop : 7; + uint32_t ph1 : 6; + uint32_t ph2 : 6; + uint32_t brp : 8; + uint32_t sjw : 5; +#else + uint32_t sjw : 5; + uint32_t brp : 8; + uint32_t ph2 : 6; + uint32_t ph1 : 6; + uint32_t prop : 7; +#endif + } s; +}; + +union ctu_can_fd_btr_fd { + uint32_t u32; + struct ctu_can_fd_btr_fd_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* BTR_FD */ + uint32_t prop_fd : 6; + uint32_t reserved_6 : 1; + uint32_t ph1_fd : 5; + uint32_t reserved_12 : 1; + uint32_t ph2_fd : 5; + uint32_t reserved_18 : 1; + uint32_t brp_fd : 8; + uint32_t sjw_fd : 5; +#else + uint32_t sjw_fd : 5; + uint32_t brp_fd : 8; + uint32_t reserved_18 : 1; + uint32_t ph2_fd : 5; + uint32_t reserved_12 : 1; + uint32_t ph1_fd : 5; + uint32_t reserved_6 : 1; + uint32_t prop_fd : 6; +#endif + } s; +}; + +union ctu_can_fd_ewl_erp_fault_state { + uint32_t u32; + struct ctu_can_fd_ewl_erp_fault_state_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* EWL */ + uint32_t ew_limit : 8; + /* ERP */ + uint32_t erp_limit : 8; + /* FAULT_STATE */ + uint32_t era : 1; + uint32_t erp : 1; + uint32_t bof : 1; + uint32_t reserved_31_19 : 13; +#else + uint32_t reserved_31_19 : 13; + uint32_t bof : 1; + uint32_t erp : 1; + uint32_t era : 1; + uint32_t erp_limit : 8; + uint32_t ew_limit : 8; +#endif + } s; +}; + +union ctu_can_fd_rec_tec { + uint32_t u32; + struct ctu_can_fd_rec_tec_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* REC */ + uint32_t rec_val : 9; + uint32_t reserved_15_9 : 7; + /* TEC */ + uint32_t tec_val : 9; + uint32_t reserved_31_25 : 7; +#else + uint32_t reserved_31_25 : 7; + uint32_t tec_val : 9; + uint32_t reserved_15_9 : 7; + uint32_t rec_val : 9; +#endif + } s; +}; + +union ctu_can_fd_err_norm_err_fd { + uint32_t u32; + struct ctu_can_fd_err_norm_err_fd_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* ERR_NORM */ + uint32_t err_norm_val : 16; + /* ERR_FD */ + uint32_t err_fd_val : 16; +#else + uint32_t err_fd_val : 16; + uint32_t err_norm_val : 16; +#endif + } s; +}; + +union ctu_can_fd_ctr_pres { + uint32_t u32; + struct ctu_can_fd_ctr_pres_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* CTR_PRES */ + uint32_t ctpv : 9; + uint32_t ptx : 1; + uint32_t prx : 1; + uint32_t enorm : 1; + uint32_t efd : 1; + uint32_t reserved_31_13 : 19; +#else + uint32_t reserved_31_13 : 19; + uint32_t efd : 1; + uint32_t enorm : 1; + uint32_t prx : 1; + uint32_t ptx : 1; + uint32_t ctpv : 9; +#endif + } s; +}; + +union ctu_can_fd_filter_a_mask { + uint32_t u32; + struct ctu_can_fd_filter_a_mask_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_A_MASK */ + uint32_t bit_mask_a_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_mask_a_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_a_val { + uint32_t u32; + struct ctu_can_fd_filter_a_val_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_A_VAL */ + uint32_t bit_val_a_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_val_a_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_b_mask { + uint32_t u32; + struct ctu_can_fd_filter_b_mask_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_B_MASK */ + uint32_t bit_mask_b_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_mask_b_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_b_val { + uint32_t u32; + struct ctu_can_fd_filter_b_val_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_B_VAL */ + uint32_t bit_val_b_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_val_b_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_c_mask { + uint32_t u32; + struct ctu_can_fd_filter_c_mask_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_C_MASK */ + uint32_t bit_mask_c_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_mask_c_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_c_val { + uint32_t u32; + struct ctu_can_fd_filter_c_val_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_C_VAL */ + uint32_t bit_val_c_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_val_c_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_ran_low { + uint32_t u32; + struct ctu_can_fd_filter_ran_low_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_RAN_LOW */ + uint32_t bit_ran_low_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_ran_low_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_ran_high { + uint32_t u32; + struct ctu_can_fd_filter_ran_high_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_RAN_HIGH */ + uint32_t bit_ran_high_val : 29; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t bit_ran_high_val : 29; +#endif + } s; +}; + +union ctu_can_fd_filter_control_filter_status { + uint32_t u32; + struct ctu_can_fd_filter_control_filter_status_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* FILTER_CONTROL */ + uint32_t fanb : 1; + uint32_t fane : 1; + uint32_t fafb : 1; + uint32_t fafe : 1; + uint32_t fbnb : 1; + uint32_t fbne : 1; + uint32_t fbfb : 1; + uint32_t fbfe : 1; + uint32_t fcnb : 1; + uint32_t fcne : 1; + uint32_t fcfb : 1; + uint32_t fcfe : 1; + uint32_t frnb : 1; + uint32_t frne : 1; + uint32_t frfb : 1; + uint32_t frfe : 1; + /* FILTER_STATUS */ + uint32_t sfa : 1; + uint32_t sfb : 1; + uint32_t sfc : 1; + uint32_t sfr : 1; + uint32_t reserved_31_20 : 12; +#else + uint32_t reserved_31_20 : 12; + uint32_t sfr : 1; + uint32_t sfc : 1; + uint32_t sfb : 1; + uint32_t sfa : 1; + uint32_t frfe : 1; + uint32_t frfb : 1; + uint32_t frne : 1; + uint32_t frnb : 1; + uint32_t fcfe : 1; + uint32_t fcfb : 1; + uint32_t fcne : 1; + uint32_t fcnb : 1; + uint32_t fbfe : 1; + uint32_t fbfb : 1; + uint32_t fbne : 1; + uint32_t fbnb : 1; + uint32_t fafe : 1; + uint32_t fafb : 1; + uint32_t fane : 1; + uint32_t fanb : 1; +#endif + } s; +}; + +union ctu_can_fd_rx_mem_info { + uint32_t u32; + struct ctu_can_fd_rx_mem_info_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* RX_MEM_INFO */ + uint32_t rx_buff_size : 13; + uint32_t reserved_15_13 : 3; + uint32_t rx_mem_free : 13; + uint32_t reserved_31_29 : 3; +#else + uint32_t reserved_31_29 : 3; + uint32_t rx_mem_free : 13; + uint32_t reserved_15_13 : 3; + uint32_t rx_buff_size : 13; +#endif + } s; +}; + +union ctu_can_fd_rx_pointers { + uint32_t u32; + struct ctu_can_fd_rx_pointers_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* RX_POINTERS */ + uint32_t rx_wpp : 12; + uint32_t reserved_15_12 : 4; + uint32_t rx_rpp : 12; + uint32_t reserved_31_28 : 4; +#else + uint32_t reserved_31_28 : 4; + uint32_t rx_rpp : 12; + uint32_t reserved_15_12 : 4; + uint32_t rx_wpp : 12; +#endif + } s; +}; + +union ctu_can_fd_rx_status_rx_settings { + uint32_t u32; + struct ctu_can_fd_rx_status_rx_settings_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* RX_STATUS */ + uint32_t rxe : 1; + uint32_t rxf : 1; + uint32_t reserved_3_2 : 2; + uint32_t rxfrc : 11; + uint32_t reserved_15 : 1; + /* RX_SETTINGS */ + uint32_t rtsop : 1; + uint32_t reserved_31_17 : 15; +#else + uint32_t reserved_31_17 : 15; + uint32_t rtsop : 1; + uint32_t reserved_15 : 1; + uint32_t rxfrc : 11; + uint32_t reserved_3_2 : 2; + uint32_t rxf : 1; + uint32_t rxe : 1; +#endif + } s; +}; + +enum ctu_can_fd_rx_settings_rtsop { + RTS_END = 0x0, + RTS_BEG = 0x1, +}; + +union ctu_can_fd_rx_data { + uint32_t u32; + struct ctu_can_fd_rx_data_s { + /* RX_DATA */ + uint32_t rx_data : 32; + } s; +}; + +union ctu_can_fd_tx_status { + uint32_t u32; + struct ctu_can_fd_tx_status_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* TX_STATUS */ + uint32_t tx1s : 4; + uint32_t tx2s : 4; + uint32_t tx3s : 4; + uint32_t tx4s : 4; + uint32_t reserved_31_16 : 16; +#else + uint32_t reserved_31_16 : 16; + uint32_t tx4s : 4; + uint32_t tx3s : 4; + uint32_t tx2s : 4; + uint32_t tx1s : 4; +#endif + } s; +}; + +enum ctu_can_fd_tx_status_tx1s { + TXT_RDY = 0x1, + TXT_TRAN = 0x2, + TXT_ABTP = 0x3, + TXT_TOK = 0x4, + TXT_ERR = 0x6, + TXT_ABT = 0x7, + TXT_ETY = 0x8, +}; + +union ctu_can_fd_tx_command { + uint32_t u32; + struct ctu_can_fd_tx_command_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* TX_COMMAND */ + uint32_t txce : 1; + uint32_t txcr : 1; + uint32_t txca : 1; + uint32_t reserved_7_3 : 5; + uint32_t txb1 : 1; + uint32_t txb2 : 1; + uint32_t txb3 : 1; + uint32_t txb4 : 1; + uint32_t reserved_31_12 : 20; +#else + uint32_t reserved_31_12 : 20; + uint32_t txb4 : 1; + uint32_t txb3 : 1; + uint32_t txb2 : 1; + uint32_t txb1 : 1; + uint32_t reserved_7_3 : 5; + uint32_t txca : 1; + uint32_t txcr : 1; + uint32_t txce : 1; +#endif + } s; +}; + +union ctu_can_fd_tx_priority { + uint32_t u32; + struct ctu_can_fd_tx_priority_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* TX_PRIORITY */ + uint32_t txt1p : 3; + uint32_t reserved_3 : 1; + uint32_t txt2p : 3; + uint32_t reserved_7 : 1; + uint32_t txt3p : 3; + uint32_t reserved_11 : 1; + uint32_t txt4p : 3; + uint32_t reserved_31_15 : 17; +#else + uint32_t reserved_31_15 : 17; + uint32_t txt4p : 3; + uint32_t reserved_11 : 1; + uint32_t txt3p : 3; + uint32_t reserved_7 : 1; + uint32_t txt2p : 3; + uint32_t reserved_3 : 1; + uint32_t txt1p : 3; +#endif + } s; +}; + +union ctu_can_fd_err_capt_alc { + uint32_t u32; + struct ctu_can_fd_err_capt_alc_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* ERR_CAPT */ + uint32_t err_pos : 5; + uint32_t err_type : 3; + uint32_t reserved_15_8 : 8; + /* ALC */ + uint32_t alc_bit : 5; + uint32_t alc_id_field : 3; + uint32_t reserved_31_24 : 8; +#else + uint32_t reserved_31_24 : 8; + uint32_t alc_id_field : 3; + uint32_t alc_bit : 5; + uint32_t reserved_15_8 : 8; + uint32_t err_type : 3; + uint32_t err_pos : 5; +#endif + } s; +}; + +enum ctu_can_fd_err_capt_err_pos { + ERC_POS_SOF = 0x0, + ERC_POS_ARB = 0x1, + ERC_POS_CTRL = 0x2, + ERC_POS_DATA = 0x3, + ERC_POS_CRC = 0x4, + ERC_POS_ACK = 0x5, + ERC_POS_EOF = 0x6, + ERC_POS_ERR = 0x7, + ERC_POS_OVRL = 0x8, + ERC_POS_OTHER = 0x1f, +}; + +enum ctu_can_fd_err_capt_err_type { + ERC_BIT_ERR = 0x0, + ERC_CRC_ERR = 0x1, + ERC_FRM_ERR = 0x2, + ERC_ACK_ERR = 0x3, + ERC_STUF_ERR = 0x4, +}; + +enum ctu_can_fd_alc_alc_id_field { + ALC_RSVD = 0x0, + ALC_BASE_ID = 0x1, + ALC_SRR_RTR = 0x2, + ALC_IDE = 0x3, + ALC_EXTENSION = 0x4, + ALC_RTR = 0x5, +}; + +union ctu_can_fd_trv_delay_ssp_cfg { + uint32_t u32; + struct ctu_can_fd_trv_delay_ssp_cfg_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* TRV_DELAY */ + uint32_t trv_delay_value : 7; + uint32_t reserved_15_7 : 9; + /* SSP_CFG */ + uint32_t ssp_offset : 8; + uint32_t ssp_src : 2; + uint32_t reserved_31_26 : 6; +#else + uint32_t reserved_31_26 : 6; + uint32_t ssp_src : 2; + uint32_t ssp_offset : 8; + uint32_t reserved_15_7 : 9; + uint32_t trv_delay_value : 7; +#endif + } s; +}; + +enum ctu_can_fd_ssp_cfg_ssp_src { + SSP_SRC_MEAS_N_OFFSET = 0x0, + SSP_SRC_NO_SSP = 0x1, + SSP_SRC_OFFSET = 0x2, +}; + +union ctu_can_fd_rx_fr_ctr { + uint32_t u32; + struct ctu_can_fd_rx_fr_ctr_s { + /* RX_FR_CTR */ + uint32_t rx_fr_ctr_val : 32; + } s; +}; + +union ctu_can_fd_tx_fr_ctr { + uint32_t u32; + struct ctu_can_fd_tx_fr_ctr_s { + /* TX_FR_CTR */ + uint32_t tx_fr_ctr_val : 32; + } s; +}; + +union ctu_can_fd_debug_register { + uint32_t u32; + struct ctu_can_fd_debug_register_s { +#ifdef __LITTLE_ENDIAN_BITFIELD + /* DEBUG_REGISTER */ + uint32_t stuff_count : 3; + uint32_t destuff_count : 3; + uint32_t pc_arb : 1; + uint32_t pc_con : 1; + uint32_t pc_dat : 1; + uint32_t pc_stc : 1; + uint32_t pc_crc : 1; + uint32_t pc_crcd : 1; + uint32_t pc_ack : 1; + uint32_t pc_ackd : 1; + uint32_t pc_eof : 1; + uint32_t pc_int : 1; + uint32_t pc_susp : 1; + uint32_t pc_ovr : 1; + uint32_t pc_sof : 1; + uint32_t reserved_31_19 : 13; +#else + uint32_t reserved_31_19 : 13; + uint32_t pc_sof : 1; + uint32_t pc_ovr : 1; + uint32_t pc_susp : 1; + uint32_t pc_int : 1; + uint32_t pc_eof : 1; + uint32_t pc_ackd : 1; + uint32_t pc_ack : 1; + uint32_t pc_crcd : 1; + uint32_t pc_crc : 1; + uint32_t pc_stc : 1; + uint32_t pc_dat : 1; + uint32_t pc_con : 1; + uint32_t pc_arb : 1; + uint32_t destuff_count : 3; + uint32_t stuff_count : 3; +#endif + } s; +}; + +union ctu_can_fd_yolo_reg { + uint32_t u32; + struct ctu_can_fd_yolo_reg_s { + /* YOLO_REG */ + uint32_t yolo_val : 32; + } s; +}; + +union ctu_can_fd_timestamp_low { + uint32_t u32; + struct ctu_can_fd_timestamp_low_s { + /* TIMESTAMP_LOW */ + uint32_t timestamp_low : 32; + } s; +}; + +union ctu_can_fd_timestamp_high { + uint32_t u32; + struct ctu_can_fd_timestamp_high_s { + /* TIMESTAMP_HIGH */ + uint32_t timestamp_high : 32; + } s; +}; + +#endif From aa406e8b7ecde584dd75fc545c41d28db7fd1082 Mon Sep 17 00:00:00 2001 From: Jan Charvat Date: Mon, 14 Sep 2020 10:13:40 +0200 Subject: [PATCH 84/86] hw/net/can: CTU CAN FD IP open hardware core emulation. The implementation of the model of complete open-source/design/hardware CAN FD controller. The IP core project has been started and is maintained by Ondrej Ille at Czech Technical University in Prague. CTU CAN FD project pages: https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core CAN bus CTU FEE Projects Listing page: http://canbus.pages.fel.cvut.cz/ The core is mapped to PCIe card same as on one of its real hardware adaptations. The device implementing two CTU CAN FD ip cores is instantiated after CAN bus definition -object can-bus,id=canbus0-bus by QEMU parameters -device ctucan_pci,canbus0=canbus0-bus,canbus1=canbus0-bus Signed-off-by: Jan Charvat Signed-off-by: Pavel Pisa Message-Id: <23e3ca4dcb2cc9900991016910a6cab7686c0e31.1600069689.git.pisa@cmp.felk.cvut.cz> Signed-off-by: Paolo Bonzini --- hw/net/Kconfig | 11 + hw/net/can/ctucan_core.c | 696 +++++++++++++++++++++++++++++++++++++++ hw/net/can/ctucan_core.h | 127 +++++++ hw/net/can/ctucan_pci.c | 281 ++++++++++++++++ hw/net/can/meson.build | 2 + 5 files changed, 1117 insertions(+) create mode 100644 hw/net/can/ctucan_core.c create mode 100644 hw/net/can/ctucan_core.h create mode 100644 hw/net/can/ctucan_pci.c diff --git a/hw/net/Kconfig b/hw/net/Kconfig index e43c96dae0..225d948841 100644 --- a/hw/net/Kconfig +++ b/hw/net/Kconfig @@ -143,3 +143,14 @@ config CAN_SJA1000 default y if PCI_DEVICES depends on PCI select CAN_BUS + +config CAN_CTUCANFD + bool + default y if PCI_DEVICES + select CAN_BUS + +config CAN_CTUCANFD_PCI + bool + default y if PCI_DEVICES + depends on PCI && CAN_CTUCANFD + select CAN_BUS diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c new file mode 100644 index 0000000000..d20835cd7e --- /dev/null +++ b/hw/net/can/ctucan_core.c @@ -0,0 +1,696 @@ +/* + * CTU CAN FD PCI device emulation + * http://canbus.pages.fel.cvut.cz/ + * + * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com) + * + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by + * Jin Yang and Pavel Pisa + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "chardev/char.h" +#include "hw/irq.h" +#include "migration/vmstate.h" +#include "net/can_emu.h" + +#include "ctucan_core.h" + +#ifndef DEBUG_CAN +#define DEBUG_CAN 0 +#endif /*DEBUG_CAN*/ + +#define DPRINTF(fmt, ...) \ + do { \ + if (DEBUG_CAN) { \ + qemu_log("[ctucan]: " fmt , ## __VA_ARGS__); \ + } \ + } while (0) + +static void ctucan_buff2frame(const uint8_t *buff, qemu_can_frame *frame) +{ + frame->can_id = 0; + frame->can_dlc = 0; + frame->flags = 0; + + if (buff == NULL) { + return; + } + { + union ctu_can_fd_frame_form_w frame_form_w; + union ctu_can_fd_identifier_w identifier_w; + unsigned int ide; + uint32_t w; + + w = le32_to_cpu(*(uint32_t *)buff); + frame_form_w = (union ctu_can_fd_frame_form_w)w; + frame->can_dlc = can_dlc2len(frame_form_w.s.dlc); + + w = le32_to_cpu(*(uint32_t *)(buff + 4)); + identifier_w = (union ctu_can_fd_identifier_w)w; + + ide = frame_form_w.s.ide; + if (ide) { + frame->can_id = (identifier_w.s.identifier_base << 18) | + identifier_w.s.identifier_ext; + frame->can_id |= QEMU_CAN_EFF_FLAG; + } else { + frame->can_id = identifier_w.s.identifier_base; + } + + if (frame_form_w.s.esi_rsv) { + frame->flags |= QEMU_CAN_FRMF_ESI; + } + + if (frame_form_w.s.rtr) { + frame->can_id |= QEMU_CAN_RTR_FLAG; + } + + if (frame_form_w.s.fdf) { /*CAN FD*/ + frame->flags |= QEMU_CAN_FRMF_TYPE_FD; + if (frame_form_w.s.brs) { + frame->flags |= QEMU_CAN_FRMF_BRS; + } + } + } + + memcpy(frame->data, buff + 0x10, 0x40); +} + + +static int ctucan_frame2buff(const qemu_can_frame *frame, uint8_t *buff) +{ + unsigned int bytes_cnt = -1; + memset(buff, 0, CTUCAN_MSG_MAX_LEN * sizeof(*buff)); + + if (frame == NULL) { + return bytes_cnt; + } + { + union ctu_can_fd_frame_form_w frame_form_w; + union ctu_can_fd_identifier_w identifier_w; + + frame_form_w.u32 = 0; + identifier_w.u32 = 0; + + bytes_cnt = frame->can_dlc; + bytes_cnt = (bytes_cnt + 3) & ~3; + bytes_cnt += 16; + frame_form_w.s.rwcnt = (bytes_cnt >> 2) - 1; + + frame_form_w.s.dlc = can_len2dlc(frame->can_dlc); + + if (frame->can_id & QEMU_CAN_EFF_FLAG) { + frame_form_w.s.ide = 1; + identifier_w.s.identifier_base = + (frame->can_id & 0x1FFC0000) >> 18; + identifier_w.s.identifier_ext = frame->can_id & 0x3FFFF; + } else { + identifier_w.s.identifier_base = frame->can_id & 0x7FF; + } + + if (frame->flags & QEMU_CAN_FRMF_ESI) { + frame_form_w.s.esi_rsv = 1; + } + + if (frame->can_id & QEMU_CAN_RTR_FLAG) { + frame_form_w.s.rtr = 1; + } + + if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) { /*CAN FD*/ + frame_form_w.s.fdf = 1; + if (frame->flags & QEMU_CAN_FRMF_BRS) { + frame_form_w.s.brs = 1; + } + } + *(uint32_t *)buff = cpu_to_le32(frame_form_w.u32); + *(uint32_t *)(buff + 4) = cpu_to_le32(identifier_w.u32); + } + + memcpy(buff + 0x10, frame->data, 0x40); + + return bytes_cnt; +} + +static void ctucan_update_irq(CtuCanCoreState *s) +{ + union ctu_can_fd_int_stat int_rq; + + int_rq.u32 = 0; + + if (s->rx_status_rx_settings.s.rxfrc) { + int_rq.s.rbnei = 1; + } + + int_rq.u32 &= ~s->int_mask.u32; + s->int_stat.u32 |= int_rq.u32; + if (s->int_stat.u32 & s->int_ena.u32) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +} + +static void ctucan_update_txnf(CtuCanCoreState *s) +{ + int i; + int txnf; + unsigned int buff_st; + + txnf = 0; + + for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { + buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf; + if (buff_st == TXT_ETY) { + txnf = 1; + } + } + s->status.s.txnf = txnf; +} + +void ctucan_hardware_reset(CtuCanCoreState *s) +{ + DPRINTF("Hardware reset in progress!!!\n"); + int i; + unsigned int buff_st; + uint32_t buff_st_mask; + + s->tx_status.u32 = 0; + for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { + buff_st_mask = 0xf << (i * 4); + buff_st = TXT_ETY; + s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) | + (buff_st << (i * 4)); + } + s->status.s.idle = 1; + + ctucan_update_txnf(s); + + s->rx_status_rx_settings.u32 = 0; + s->rx_tail_pos = 0; + s->rx_cnt = 0; + s->rx_frame_rem = 0; + + /* Flush RX buffer */ + s->rx_tail_pos = 0; + s->rx_cnt = 0; + s->rx_frame_rem = 0; + + /* Set on progdokum reset value */ + s->mode_settings.u32 = 0; + s->mode_settings.s.fde = 1; + + s->int_stat.u32 = 0; + s->int_ena.u32 = 0; + s->int_mask.u32 = 0; + + s->rx_status_rx_settings.u32 = 0; + s->rx_status_rx_settings.s.rxe = 0; + + s->rx_fr_ctr.u32 = 0; + s->tx_fr_ctr.u32 = 0; + + s->yolo_reg.s.yolo_val = 3735928559; + + qemu_irq_lower(s->irq); +} + +static void ctucan_send_ready_buffers(CtuCanCoreState *s) +{ + qemu_can_frame frame; + uint8_t *pf; + int buff2tx_idx; + uint32_t tx_prio_max; + unsigned int buff_st; + uint32_t buff_st_mask; + + if (!s->mode_settings.s.ena) { + return; + } + + do { + union ctu_can_fd_int_stat int_stat; + int i; + buff2tx_idx = -1; + tx_prio_max = 0; + + for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { + uint32_t prio; + + buff_st_mask = 0xf << (i * 4); + buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf; + + if (buff_st != TXT_RDY) { + continue; + } + prio = (s->tx_priority.u32 >> (i * 4)) & 0x7; + if (tx_prio_max < prio) { + tx_prio_max = prio; + buff2tx_idx = i; + } + } + if (buff2tx_idx == -1) { + break; + } + buff_st_mask = 0xf << (buff2tx_idx * 4); + buff_st = (s->tx_status.u32 >> (buff2tx_idx * 4)) & 0xf; + int_stat.u32 = 0; + buff_st = TXT_RDY; + pf = s->tx_buffer[buff2tx_idx].data; + ctucan_buff2frame(pf, &frame); + s->status.s.idle = 0; + s->status.s.txs = 1; + can_bus_client_send(&s->bus_client, &frame, 1); + s->status.s.idle = 1; + s->status.s.txs = 0; + s->tx_fr_ctr.s.tx_fr_ctr_val++; + buff_st = TXT_TOK; + int_stat.s.txi = 1; + int_stat.s.txbhci = 1; + s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32; + s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) | + (buff_st << (buff2tx_idx * 4)); + } while (1); +} + +#define CTUCAN_CORE_TXBUFF_SPAN \ + (CTU_CAN_FD_TXTB2_DATA_1 - CTU_CAN_FD_TXTB1_DATA_1) + +void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val, + unsigned size) +{ + int i; + + DPRINTF("write 0x%02llx addr 0x%02x\n", + (unsigned long long)val, (unsigned int)addr); + + if (addr > CTUCAN_CORE_MEM_SIZE) { + return; + } + + if (addr >= CTU_CAN_FD_TXTB1_DATA_1) { + int buff_num; + addr -= CTU_CAN_FD_TXTB1_DATA_1; + buff_num = addr / CTUCAN_CORE_TXBUFF_SPAN; + addr %= CTUCAN_CORE_TXBUFF_SPAN; + if (buff_num < CTUCAN_CORE_TXBUF_NUM) { + uint32_t *bufp = (uint32_t *)(s->tx_buffer[buff_num].data + addr); + *bufp = cpu_to_le32(val); + } + } else { + switch (addr & ~3) { + case CTU_CAN_FD_MODE: + s->mode_settings.u32 = (uint32_t)val; + if (s->mode_settings.s.rst) { + ctucan_hardware_reset(s); + s->mode_settings.s.rst = 0; + } + break; + case CTU_CAN_FD_COMMAND: + { + union ctu_can_fd_command command; + command.u32 = (uint32_t)val; + if (command.s.cdo) { + s->status.s.dor = 0; + } + if (command.s.rrb) { + s->rx_tail_pos = 0; + s->rx_cnt = 0; + s->rx_frame_rem = 0; + s->rx_status_rx_settings.s.rxfrc = 0; + } + if (command.s.txfcrst) { + s->tx_fr_ctr.s.tx_fr_ctr_val = 0; + } + if (command.s.rxfcrst) { + s->rx_fr_ctr.s.rx_fr_ctr_val = 0; + } + break; + } + case CTU_CAN_FD_INT_STAT: + s->int_stat.u32 &= ~(uint32_t)val; + break; + case CTU_CAN_FD_INT_ENA_SET: + s->int_ena.u32 |= (uint32_t)val; + break; + case CTU_CAN_FD_INT_ENA_CLR: + s->int_ena.u32 &= ~(uint32_t)val; + break; + case CTU_CAN_FD_INT_MASK_SET: + s->int_mask.u32 |= (uint32_t)val; + break; + case CTU_CAN_FD_INT_MASK_CLR: + s->int_mask.u32 &= ~(uint32_t)val; + break; + case CTU_CAN_FD_TX_COMMAND: + if (s->mode_settings.s.ena) { + union ctu_can_fd_tx_command tx_command; + union ctu_can_fd_tx_command mask; + unsigned int buff_st; + uint32_t buff_st_mask; + + tx_command.u32 = (uint32_t)val; + mask.u32 = 0; + mask.s.txb1 = 1; + + for (i = 0; i < CTUCAN_CORE_TXBUF_NUM; i++) { + if (!(tx_command.u32 & (mask.u32 << i))) { + continue; + } + buff_st_mask = 0xf << (i * 4); + buff_st = (s->tx_status.u32 >> (i * 4)) & 0xf; + if (tx_command.s.txca) { + if (buff_st == TXT_RDY) { + buff_st = TXT_ABT; + } + } + if (tx_command.s.txcr) { + if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) || + (buff_st == TXT_ABT) || (buff_st == TXT_ETY)) + buff_st = TXT_RDY; + } + if (tx_command.s.txce) { + if ((buff_st == TXT_TOK) || (buff_st == TXT_ERR) || + (buff_st == TXT_ABT)) + buff_st = TXT_ETY; + } + s->tx_status.u32 = (s->tx_status.u32 & ~buff_st_mask) | + (buff_st << (i * 4)); + } + + ctucan_send_ready_buffers(s); + ctucan_update_txnf(s); + } + break; + case CTU_CAN_FD_TX_PRIORITY: + s->tx_priority.u32 = (uint32_t)val; + break; + } + + ctucan_update_irq(s); + } + + return; +} + +uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size) +{ + uint32_t val = 0; + + DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr); + + if (addr > CTUCAN_CORE_MEM_SIZE) { + return 0; + } + + switch (addr & ~3) { + case CTU_CAN_FD_DEVICE_ID: + { + union ctu_can_fd_device_id_version idver; + idver.u32 = 0; + idver.s.device_id = CTU_CAN_FD_ID; + idver.s.ver_major = 2; + idver.s.ver_minor = 2; + val = idver.u32; + } + break; + case CTU_CAN_FD_MODE: + val = s->mode_settings.u32; + break; + case CTU_CAN_FD_STATUS: + val = s->status.u32; + break; + case CTU_CAN_FD_INT_STAT: + val = s->int_stat.u32; + break; + case CTU_CAN_FD_INT_ENA_SET: + case CTU_CAN_FD_INT_ENA_CLR: + val = s->int_ena.u32; + break; + case CTU_CAN_FD_INT_MASK_SET: + case CTU_CAN_FD_INT_MASK_CLR: + val = s->int_mask.u32; + break; + case CTU_CAN_FD_RX_MEM_INFO: + s->rx_mem_info.u32 = 0; + s->rx_mem_info.s.rx_buff_size = CTUCAN_RCV_BUF_LEN >> 2; + s->rx_mem_info.s.rx_mem_free = (CTUCAN_RCV_BUF_LEN - + s->rx_cnt) >> 2; + val = s->rx_mem_info.u32; + break; + case CTU_CAN_FD_RX_POINTERS: + { + uint32_t rx_head_pos = s->rx_tail_pos + s->rx_cnt; + rx_head_pos %= CTUCAN_RCV_BUF_LEN; + s->rx_pointers.s.rx_wpp = rx_head_pos; + s->rx_pointers.s.rx_rpp = s->rx_tail_pos; + val = s->rx_pointers.u32; + break; + } + case CTU_CAN_FD_RX_STATUS: + case CTU_CAN_FD_RX_SETTINGS: + if (!s->rx_status_rx_settings.s.rxfrc) { + s->rx_status_rx_settings.s.rxe = 1; + } else { + s->rx_status_rx_settings.s.rxe = 0; + } + if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) { + s->rx_status_rx_settings.s.rxf = 1; + } else { + s->rx_status_rx_settings.s.rxf = 0; + } + val = s->rx_status_rx_settings.u32; + break; + case CTU_CAN_FD_RX_DATA: + if (s->rx_cnt) { + memcpy(&val, s->rx_buff + s->rx_tail_pos, 4); + val = le32_to_cpu(val); + if (!s->rx_frame_rem) { + union ctu_can_fd_frame_form_w frame_form_w; + frame_form_w.u32 = val; + s->rx_frame_rem = frame_form_w.s.rwcnt * 4 + 4; + } + s->rx_cnt -= 4; + s->rx_frame_rem -= 4; + if (!s->rx_frame_rem) { + s->rx_status_rx_settings.s.rxfrc--; + if (!s->rx_status_rx_settings.s.rxfrc) { + s->status.s.rxne = 0; + s->status.s.idle = 1; + s->status.s.rxs = 0; + } + } + s->rx_tail_pos = (s->rx_tail_pos + 4) % CTUCAN_RCV_BUF_LEN; + } else { + val = 0; + } + break; + case CTU_CAN_FD_TX_STATUS: + val = s->tx_status.u32; + break; + case CTU_CAN_FD_TX_PRIORITY: + val = s->tx_priority.u32; + break; + case CTU_CAN_FD_RX_FR_CTR: + val = s->rx_fr_ctr.s.rx_fr_ctr_val; + break; + case CTU_CAN_FD_TX_FR_CTR: + val = s->tx_fr_ctr.s.tx_fr_ctr_val; + break; + case CTU_CAN_FD_YOLO_REG: + val = s->yolo_reg.s.yolo_val; + break; + } + + val >>= ((addr & 3) << 3); + if (size < 8) { + val &= ((uint64_t)1 << (size << 3)) - 1; + } + + return val; +} + +bool ctucan_can_receive(CanBusClientState *client) +{ + CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client); + + if (!s->mode_settings.s.ena) { + return false; + } + + return true; /* always return true, when operation mode */ +} + +ssize_t ctucan_receive(CanBusClientState *client, const qemu_can_frame *frames, + size_t frames_cnt) +{ + CtuCanCoreState *s = container_of(client, CtuCanCoreState, bus_client); + static uint8_t rcv[CTUCAN_MSG_MAX_LEN]; + int i; + int ret = -1; + const qemu_can_frame *frame = frames; + union ctu_can_fd_int_stat int_stat; + int_stat.u32 = 0; + + if (frames_cnt <= 0) { + return 0; + } + + ret = ctucan_frame2buff(frame, rcv); + + if (s->rx_cnt + ret > CTUCAN_RCV_BUF_LEN) { /* Data overrun. */ + s->status.s.dor = 1; + int_stat.s.doi = 1; + s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32; + ctucan_update_irq(s); + DPRINTF("Receive FIFO overrun\n"); + return ret; + } + s->status.s.idle = 0; + s->status.s.rxs = 1; + int_stat.s.rxi = 1; + if (((s->rx_cnt + 3) & ~3) == CTUCAN_RCV_BUF_LEN) { + int_stat.s.rxfi = 1; + } + s->int_stat.u32 |= int_stat.u32 & ~s->int_mask.u32; + s->rx_fr_ctr.s.rx_fr_ctr_val++; + s->rx_status_rx_settings.s.rxfrc++; + for (i = 0; i < ret; i++) { + s->rx_buff[(s->rx_tail_pos + s->rx_cnt) % CTUCAN_RCV_BUF_LEN] = rcv[i]; + s->rx_cnt++; + } + s->status.s.rxne = 1; + + ctucan_update_irq(s); + + return 1; +} + +static CanBusClientInfo ctucan_bus_client_info = { + .can_receive = ctucan_can_receive, + .receive = ctucan_receive, +}; + + +int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus) +{ + s->bus_client.info = &ctucan_bus_client_info; + + if (!bus) { + return -EINVAL; + } + + if (can_bus_insert_client(bus, &s->bus_client) < 0) { + return -1; + } + + return 0; +} + +void ctucan_disconnect(CtuCanCoreState *s) +{ + can_bus_remove_client(&s->bus_client); +} + +int ctucan_init(CtuCanCoreState *s, qemu_irq irq) +{ + s->irq = irq; + + qemu_irq_lower(s->irq); + + ctucan_hardware_reset(s); + + return 0; +} + +const VMStateDescription vmstate_qemu_ctucan_tx_buffer = { + .name = "qemu_ctucan_tx_buffer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN), + VMSTATE_END_OF_LIST() + } +}; + +static int ctucan_post_load(void *opaque, int version_id) +{ + CtuCanCoreState *s = opaque; + ctucan_update_irq(s); + return 0; +} + +/* VMState is needed for live migration of QEMU images */ +const VMStateDescription vmstate_ctucan = { + .name = "ctucan", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ctucan_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState), + VMSTATE_UINT32(status.u32, CtuCanCoreState), + VMSTATE_UINT32(int_stat.u32, CtuCanCoreState), + VMSTATE_UINT32(int_ena.u32, CtuCanCoreState), + VMSTATE_UINT32(int_mask.u32, CtuCanCoreState), + VMSTATE_UINT32(brt.u32, CtuCanCoreState), + VMSTATE_UINT32(brt_fd.u32, CtuCanCoreState), + VMSTATE_UINT32(ewl_erp_fault_state.u32, CtuCanCoreState), + VMSTATE_UINT32(rec_tec.u32, CtuCanCoreState), + VMSTATE_UINT32(err_norm_err_fd.u32, CtuCanCoreState), + VMSTATE_UINT32(ctr_pres.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_a_mask.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_a_val.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_b_mask.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_b_val.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_c_mask.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_c_val.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_ran_low.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_ran_high.u32, CtuCanCoreState), + VMSTATE_UINT32(filter_control_filter_status.u32, CtuCanCoreState), + VMSTATE_UINT32(rx_mem_info.u32, CtuCanCoreState), + VMSTATE_UINT32(rx_pointers.u32, CtuCanCoreState), + VMSTATE_UINT32(rx_status_rx_settings.u32, CtuCanCoreState), + VMSTATE_UINT32(tx_status.u32, CtuCanCoreState), + VMSTATE_UINT32(tx_priority.u32, CtuCanCoreState), + VMSTATE_UINT32(err_capt_alc.u32, CtuCanCoreState), + VMSTATE_UINT32(trv_delay_ssp_cfg.u32, CtuCanCoreState), + VMSTATE_UINT32(rx_fr_ctr.u32, CtuCanCoreState), + VMSTATE_UINT32(tx_fr_ctr.u32, CtuCanCoreState), + VMSTATE_UINT32(debug_register.u32, CtuCanCoreState), + VMSTATE_UINT32(yolo_reg.u32, CtuCanCoreState), + VMSTATE_UINT32(timestamp_low.u32, CtuCanCoreState), + VMSTATE_UINT32(timestamp_high.u32, CtuCanCoreState), + + VMSTATE_STRUCT_ARRAY(tx_buffer, CtuCanCoreState, + CTUCAN_CORE_TXBUF_NUM, 0, vmstate_qemu_ctucan_tx_buffer, + CtuCanCoreMsgBuffer), + + VMSTATE_BUFFER(rx_buff, CtuCanCoreState), + VMSTATE_UINT32(rx_tail_pos, CtuCanCoreState), + VMSTATE_UINT32(rx_cnt, CtuCanCoreState), + VMSTATE_UINT32(rx_frame_rem, CtuCanCoreState), + + VMSTATE_END_OF_LIST() + } +}; diff --git a/hw/net/can/ctucan_core.h b/hw/net/can/ctucan_core.h new file mode 100644 index 0000000000..f21cb1c5ec --- /dev/null +++ b/hw/net/can/ctucan_core.h @@ -0,0 +1,127 @@ +/* + * CTU CAN FD device emulation + * http://canbus.pages.fel.cvut.cz/ + * + * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com) + * + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by + * Jin Yang and Pavel Pisa + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef HW_CAN_CTUCAN_CORE_H +#define HW_CAN_CTUCAN_CORE_H + +#include "exec/hwaddr.h" +#include "net/can_emu.h" + + +#ifndef __LITTLE_ENDIAN_BITFIELD +#define __LITTLE_ENDIAN_BITFIELD 1 +#endif + +#include "ctu_can_fd_frame.h" +#include "ctu_can_fd_regs.h" + +#define CTUCAN_CORE_MEM_SIZE 0x500 + +/* The max size for a message in FIFO */ +#define CTUCAN_MSG_MAX_LEN (CTU_CAN_FD_DATA_1_4_W + 64) +/* The receive buffer size. */ +#define CTUCAN_RCV_BUF_LEN (1024 * 8) + + +/* The max size for a message buffer */ +#define CTUCAN_CORE_MSG_MAX_LEN 0x50 +/* The receive buffer size. */ +#define CTUCAN_CORE_RCV_BUF_LEN 0x1000 + +#define CTUCAN_CORE_TXBUF_NUM 4 + +typedef struct CtuCanCoreMsgBuffer { + uint8_t data[CTUCAN_CORE_MSG_MAX_LEN]; +} CtuCanCoreMsgBuffer; + +typedef struct CtuCanCoreState { + union ctu_can_fd_mode_settings mode_settings; + union ctu_can_fd_status status; + union ctu_can_fd_int_stat int_stat; + union ctu_can_fd_int_ena_set int_ena; + union ctu_can_fd_int_mask_set int_mask; + union ctu_can_fd_btr brt; + union ctu_can_fd_btr_fd brt_fd; + union ctu_can_fd_ewl_erp_fault_state ewl_erp_fault_state; + union ctu_can_fd_rec_tec rec_tec; + union ctu_can_fd_err_norm_err_fd err_norm_err_fd; + union ctu_can_fd_ctr_pres ctr_pres; + union ctu_can_fd_filter_a_mask filter_a_mask; + union ctu_can_fd_filter_a_val filter_a_val; + union ctu_can_fd_filter_b_mask filter_b_mask; + union ctu_can_fd_filter_b_val filter_b_val; + union ctu_can_fd_filter_c_mask filter_c_mask; + union ctu_can_fd_filter_c_val filter_c_val; + union ctu_can_fd_filter_ran_low filter_ran_low; + union ctu_can_fd_filter_ran_high filter_ran_high; + union ctu_can_fd_filter_control_filter_status filter_control_filter_status; + union ctu_can_fd_rx_mem_info rx_mem_info; + union ctu_can_fd_rx_pointers rx_pointers; + union ctu_can_fd_rx_status_rx_settings rx_status_rx_settings; + union ctu_can_fd_tx_status tx_status; + union ctu_can_fd_tx_priority tx_priority; + union ctu_can_fd_err_capt_alc err_capt_alc; + union ctu_can_fd_trv_delay_ssp_cfg trv_delay_ssp_cfg; + union ctu_can_fd_rx_fr_ctr rx_fr_ctr; + union ctu_can_fd_tx_fr_ctr tx_fr_ctr; + union ctu_can_fd_debug_register debug_register; + union ctu_can_fd_yolo_reg yolo_reg; + union ctu_can_fd_timestamp_low timestamp_low; + union ctu_can_fd_timestamp_high timestamp_high; + + CtuCanCoreMsgBuffer tx_buffer[CTUCAN_CORE_TXBUF_NUM]; + + uint8_t rx_buff[CTUCAN_RCV_BUF_LEN]; /* 32~95 .. 64bytes Rx FIFO */ + uint32_t rx_tail_pos; /* Count by bytes. */ + uint32_t rx_cnt; /* Count by bytes. */ + uint32_t rx_frame_rem; + + qemu_irq irq; + CanBusClientState bus_client; +} CtuCanCoreState; + +void ctucan_hardware_reset(CtuCanCoreState *s); + +void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val, + unsigned size); + +uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size); + +int ctucan_connect_to_bus(CtuCanCoreState *s, CanBusState *bus); + +void ctucan_disconnect(CtuCanCoreState *s); + +int ctucan_init(CtuCanCoreState *s, qemu_irq irq); + +bool ctucan_can_receive(CanBusClientState *client); + +ssize_t ctucan_receive(CanBusClientState *client, + const qemu_can_frame *frames, size_t frames_cnt); + +extern const VMStateDescription vmstate_ctucan; + +#endif diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c new file mode 100644 index 0000000000..f1c86cd06a --- /dev/null +++ b/hw/net/can/ctucan_pci.c @@ -0,0 +1,281 @@ +/* + * CTU CAN FD PCI device emulation + * http://canbus.pages.fel.cvut.cz/ + * + * Copyright (c) 2019 Jan Charvat (jancharvat.charvat@gmail.com) + * + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by + * Jin Yang and Pavel Pisa + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/event_notifier.h" +#include "qemu/module.h" +#include "qemu/thread.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "chardev/char.h" +#include "hw/irq.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "net/can_emu.h" + +#include "ctucan_core.h" + +#define TYPE_CTUCAN_PCI_DEV "ctucan_pci" + +typedef struct CtuCanPCIState CtuCanPCIState; +DECLARE_INSTANCE_CHECKER(CtuCanPCIState, CTUCAN_PCI_DEV, + TYPE_CTUCAN_PCI_DEV) + +#define CTUCAN_PCI_CORE_COUNT 2 +#define CTUCAN_PCI_CORE_RANGE 0x10000 + +#define CTUCAN_PCI_BAR_COUNT 2 + +#define CTUCAN_PCI_BYTES_PER_CORE 0x4000 + +#ifndef PCI_VENDOR_ID_TEDIA +#define PCI_VENDOR_ID_TEDIA 0x1760 +#endif + +#define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00 + +#define CTUCAN_BAR0_RANGE 0x8000 +#define CTUCAN_BAR0_CTUCAN_ID 0x0000 +#define CTUCAN_BAR0_CRA_BASE 0x4000 +#define CYCLONE_IV_CRA_A2P_IE (0x0050) + +#define CTUCAN_WITHOUT_CTUCAN_ID 0 +#define CTUCAN_WITH_CTUCAN_ID 1 + +struct CtuCanPCIState { + /*< private >*/ + PCIDevice dev; + /*< public >*/ + MemoryRegion ctucan_io[CTUCAN_PCI_BAR_COUNT]; + + CtuCanCoreState ctucan_state[CTUCAN_PCI_CORE_COUNT]; + qemu_irq irq; + + char *model; /* The model that support, only SJA1000 now. */ + CanBusState *canbus[CTUCAN_PCI_CORE_COUNT]; +}; + +static void ctucan_pci_reset(DeviceState *dev) +{ + CtuCanPCIState *d = CTUCAN_PCI_DEV(dev); + int i; + + for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { + ctucan_hardware_reset(&d->ctucan_state[i]); + } +} + +static uint64_t ctucan_pci_id_cra_io_read(void *opaque, hwaddr addr, + unsigned size) +{ + if (addr >= 4) { + return 0; + } + + uint64_t tmp = 0xC0000000 + CTUCAN_PCI_CORE_COUNT; + tmp >>= ((addr & 3) << 3); + if (size < 8) { + tmp &= ((uint64_t)1 << (size << 3)) - 1; + } + return tmp; +} + +static void ctucan_pci_id_cra_io_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + +} + +static uint64_t ctucan_pci_cores_io_read(void *opaque, hwaddr addr, + unsigned size) +{ + CtuCanPCIState *d = opaque; + CtuCanCoreState *s; + hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE; + + if (core_num >= CTUCAN_PCI_CORE_COUNT) { + return 0; + } + + s = &d->ctucan_state[core_num]; + + return ctucan_mem_read(s, addr % CTUCAN_PCI_BYTES_PER_CORE, size); +} + +static void ctucan_pci_cores_io_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + CtuCanPCIState *d = opaque; + CtuCanCoreState *s; + hwaddr core_num = addr / CTUCAN_PCI_BYTES_PER_CORE; + + if (core_num >= CTUCAN_PCI_CORE_COUNT) { + return; + } + + s = &d->ctucan_state[core_num]; + + return ctucan_mem_write(s, addr % CTUCAN_PCI_BYTES_PER_CORE, data, size); +} + +static const MemoryRegionOps ctucan_pci_id_cra_io_ops = { + .read = ctucan_pci_id_cra_io_read, + .write = ctucan_pci_id_cra_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 1, + .impl.max_access_size = 4, + .valid.min_access_size = 1, + .valid.max_access_size = 4, +}; + +static const MemoryRegionOps ctucan_pci_cores_io_ops = { + .read = ctucan_pci_cores_io_read, + .write = ctucan_pci_cores_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 1, + .impl.max_access_size = 4, + .valid.min_access_size = 1, + .valid.max_access_size = 4, +}; + +static void ctucan_pci_realize(PCIDevice *pci_dev, Error **errp) +{ + CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev); + uint8_t *pci_conf; + int i; + + pci_conf = pci_dev->config; + pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ + + d->irq = pci_allocate_irq(&d->dev); + + for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { + ctucan_init(&d->ctucan_state[i], d->irq); + } + + for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { + if (ctucan_connect_to_bus(&d->ctucan_state[i], d->canbus[i]) < 0) { + error_setg(errp, "ctucan_connect_to_bus failed"); + return; + } + } + + memory_region_init_io(&d->ctucan_io[0], OBJECT(d), + &ctucan_pci_id_cra_io_ops, d, + "ctucan_pci-core0", CTUCAN_BAR0_RANGE); + memory_region_init_io(&d->ctucan_io[1], OBJECT(d), + &ctucan_pci_cores_io_ops, d, + "ctucan_pci-core1", CTUCAN_PCI_CORE_RANGE); + + for (i = 0 ; i < CTUCAN_PCI_BAR_COUNT; i++) { + pci_register_bar(&d->dev, i, PCI_BASE_ADDRESS_MEM_MASK & 0, + &d->ctucan_io[i]); + } +} + +static void ctucan_pci_exit(PCIDevice *pci_dev) +{ + CtuCanPCIState *d = CTUCAN_PCI_DEV(pci_dev); + int i; + + for (i = 0 ; i < CTUCAN_PCI_CORE_COUNT; i++) { + ctucan_disconnect(&d->ctucan_state[i]); + } + + qemu_free_irq(d->irq); +} + +static const VMStateDescription vmstate_ctucan_pci = { + .name = "ctucan_pci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, CtuCanPCIState), + VMSTATE_STRUCT(ctucan_state[0], CtuCanPCIState, 0, vmstate_ctucan, + CtuCanCoreState), +#if CTUCAN_PCI_CORE_COUNT >= 2 + VMSTATE_STRUCT(ctucan_state[1], CtuCanPCIState, 0, vmstate_ctucan, + CtuCanCoreState), +#endif + VMSTATE_END_OF_LIST() + } +}; + +static void ctucan_pci_instance_init(Object *obj) +{ + CtuCanPCIState *d = CTUCAN_PCI_DEV(obj); + + object_property_add_link(obj, "canbus0", TYPE_CAN_BUS, + (Object **)&d->canbus[0], + qdev_prop_allow_set_link_before_realize, 0); +#if CTUCAN_PCI_CORE_COUNT >= 2 + object_property_add_link(obj, "canbus1", TYPE_CAN_BUS, + (Object **)&d->canbus[1], + qdev_prop_allow_set_link_before_realize, 0); +#endif +} + +static void ctucan_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = ctucan_pci_realize; + k->exit = ctucan_pci_exit; + k->vendor_id = PCI_VENDOR_ID_TEDIA; + k->device_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21; + k->revision = 0x00; + k->class_id = 0x000c09; + k->subsystem_vendor_id = PCI_VENDOR_ID_TEDIA; + k->subsystem_id = PCI_DEVICE_ID_TEDIA_CTUCAN_VER21; + dc->desc = "CTU CAN PCI"; + dc->vmsd = &vmstate_ctucan_pci; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->reset = ctucan_pci_reset; +} + +static const TypeInfo ctucan_pci_info = { + .name = TYPE_CTUCAN_PCI_DEV, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(CtuCanPCIState), + .class_init = ctucan_pci_class_init, + .instance_init = ctucan_pci_instance_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static void ctucan_pci_register_types(void) +{ + type_register_static(&ctucan_pci_info); +} + +type_init(ctucan_pci_register_types) diff --git a/hw/net/can/meson.build b/hw/net/can/meson.build index c9cfeb7954..714951f375 100644 --- a/hw/net/can/meson.build +++ b/hw/net/can/meson.build @@ -2,3 +2,5 @@ softmmu_ss.add(when: 'CONFIG_CAN_SJA1000', if_true: files('can_sja1000.c')) softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_kvaser_pci.c')) softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_pcm3680_pci.c')) softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_mioe3680_pci.c')) +softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD', if_true: files('ctucan_core.c')) +softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD_PCI', if_true: files('ctucan_pci.c')) From de4d4adb5875482756396f24b959b03fe3ce8575 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Mon, 14 Sep 2020 10:13:41 +0200 Subject: [PATCH 85/86] hw/net/can: Documentation for CTU CAN FD IP open hardware core emulation. Updated MAINTAINERS for CAN bus related emulation as well. Signed-off-by: Pavel Pisa Message-Id: <6d1b8db69efc4e5cfad702d2150e1960e8f63572.1600069689.git.pisa@cmp.felk.cvut.cz> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 9 ++++ docs/can.txt | 113 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index ffcf222243..ade1100202 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2091,6 +2091,15 @@ F: hw/rx/ F: include/hw/intc/rx_icu.h F: include/hw/rx/ +CAN bus subsystem and hardware +M: Pavel Pisa +M: Vikram Garhwal +S: Maintained +W: https://canbus.pages.fel.cvut.cz/ +F: net/can/* +F: hw/net/can/* +F: include/net/can_*.h + Subsystems ---------- Audio diff --git a/docs/can.txt b/docs/can.txt index 11ed8f2d68..5838f6620c 100644 --- a/docs/can.txt +++ b/docs/can.txt @@ -8,13 +8,22 @@ can be connected to host system CAN API (at this time only Linux SocketCAN is supported). The concept of busses is generic and different CAN controllers -can be implemented for it but at this time only SJA1000 chip -controller is implemented. +can be implemented. + +The initial submission implemented SJA1000 controller which +is common and well supported by by drivers for the most operating +systems. The PCI addon card hardware has been selected as the first CAN interface to implement because such device can be easily connected to systems with different CPU architectures (x86, PowerPC, Arm, etc.). +In 2020, CTU CAN FD controller model has been added as part +of the bachelor theses of Jan Charvat. This controller is complete +open-source/design/hardware solution. The core designer +of the project is Ondrej Ille, the financial support has been +provided by CTU, and more companies including Volkswagen subsidiaries. + The project has been initially started in frame of RTEMS GSoC 2013 slot by Jin Yang under our mentoring The initial idea was to provide generic CAN subsystem for RTEMS. But lack of common environment for code and RTEMS @@ -22,8 +31,8 @@ testing lead to goal change to provide environment which provides complete emulated environment for testing and RTEMS GSoC slot has been donated to work on CAN hardware emulation on QEMU. -Examples how to use CAN emulation -================================= +Examples how to use CAN emulation for SJA1000 based borads +========================================================== When QEMU with CAN PCI support is compiled then one of the next CAN boards can be selected @@ -90,18 +99,100 @@ traffic with "candump" command which is included in "can-utils". candump can0 +CTU CAN FD support examples +=========================== + +This open-source core provides CAN FD support. CAN FD drames are +delivered even to the host systems when SocketCAN interface is found +CAN FD capable. + +The PCIe borad emulation is provided for now (the device identifier is +ctucan_pci). The defauld build defines two CTU CAN FD cores +on the board. + +Example how to connect the canbus0-bus (virtual wire) to the host +Linux system (SocketCAN used) and to both CTU CAN FD cores emulated +on the corresponding PCI card expects that host system CAN bus +is setup according to the previous SJA1000 section. + + qemu-system-x86_64 -enable-kvm -kernel /boot/vmlinuz-4.19.52+ \ + -initrd ramdisk.cpio \ + -virtfs local,path=shareddir,security_model=none,mount_tag=shareddir \ + -vga cirrus \ + -append "console=ttyS0" \ + -object can-bus,id=canbus0-bus \ + -object can-host-socketcan,if=can0,canbus=canbus0-bus,id=canbus0-socketcan \ + -device ctucan_pci,canbus0=canbus0-bus,canbus1=canbus0-bus \ + -nographic + +Setup of CTU CAN FD controller in a guest Linux system + + insmod ctucanfd.ko || modprobe ctucanfd + insmod ctucanfd_pci.ko || modprobe ctucanfd_pci + + for ifc in /sys/class/net/can* ; do + if [ -e $ifc/device/vendor ] ; then + if ! grep -q 0x1760 $ifc/device/vendor ; then + continue; + fi + else + continue; + fi + if [ -e $ifc/device/device ] ; then + if ! grep -q 0xff00 $ifc/device/device ; then + continue; + fi + else + continue; + fi + ifc=$(basename $ifc) + /bin/ip link set $ifc type can bitrate 1000000 dbitrate 10000000 fd on + /bin/ip link set $ifc up + done + +The test can run for example + + candump can1 + +in the guest system and next commands in the host system for basic CAN + + cangen can0 + +for CAN FD without bitrate switch + + cangen can0 -f + +and with bitrate switch + + cangen can0 -b + +The test can be run viceversa, generate messages in the guest system and capture them +in the host one and much more combinations. + Links to other resources ======================== - (1) Repository with development branch can-pci at Czech Technical University - https://gitlab.fel.cvut.cz/canbus/qemu-canbus - (2) GitHub repository with can-pci and our other changes included + (1) CAN related projects at Czech Technical University, Faculty of Electrical Engineering + http://canbus.pages.fel.cvut.cz/ + (2) Repository with development can-pci branch at Czech Technical University https://gitlab.fel.cvut.cz/canbus/qemu-canbus (3) RTEMS page describing project https://devel.rtems.org/wiki/Developer/Simulators/QEMU/CANEmulation (4) RTLWS 2015 article about the project and its use with CANopen emulation - http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can.pdf - Slides - http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can-slides.pdf - (5) Linux SocketCAN utilities + http://cmp.felk.cvut.cz/~pisa/can/doc/rtlws-17-pisa-qemu-can.pdf + (5) GNU/Linux, CAN and CANopen in Real-time Control Applications + Slides from LinuxDays 2017 (include updated RTLWS 2015 content) + https://www.linuxdays.cz/2017/video/Pavel_Pisa-CAN_canopen.pdf + (6) Linux SocketCAN utilities https://github.com/linux-can/can-utils/ + (7) CTU CAN FD project including core VHDL design, Linux driver, + test utilities etc. + https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core + (8) CTU CAN FD Core Datasheet Documentation + http://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/Progdokum.pdf + (9) CTU CAN FD Core System Architecture Documentation + http://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/ctu_can_fd_architecture.pdf + (10) CTU CAN FD Driver Documentation + http://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/driver_doc/ctucanfd-driver.html + (11) Integration with PCIe interfacing for Intel/Altera Cyclone IV based board + https://gitlab.fel.cvut.cz/canbus/pcie-ctu_can_fd From 37aeb7a28ddbf52dd25dd53ae1b8391bc2287858 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Mon, 14 Sep 2020 10:13:42 +0200 Subject: [PATCH 86/86] hw/net/can: Correct Kconfig dependencies The original CAN_PCI config option enables multiple SJA1000 PCI boards emulation build. These boards bridge SJA1000 into I/O or memory address space of the host CPU and depend on SJA1000 emulation. Signed-off-by: Pavel Pisa Message-Id: Signed-off-by: Paolo Bonzini --- hw/net/Kconfig | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/net/Kconfig b/hw/net/Kconfig index 225d948841..6d795ec752 100644 --- a/hw/net/Kconfig +++ b/hw/net/Kconfig @@ -132,16 +132,15 @@ config ROCKER config CAN_BUS bool -config CAN_PCI - bool - default y if PCI_DEVICES - depends on PCI - select CAN_BUS - config CAN_SJA1000 bool default y if PCI_DEVICES - depends on PCI + select CAN_BUS + +config CAN_PCI + bool + default y if PCI_DEVICES + depends on PCI && CAN_SJA1000 select CAN_BUS config CAN_CTUCANFD