From: Oliver Upton <hidden> Date: 2021-08-04 09:01:26
KVM's current means of saving/restoring system counters is plagued with
temporal issues. At least on ARM64 and x86, we migrate the guest's
system counter by-value through the respective guest system register
values (cntvct_el0, ia32_tsc). Restoring system counters by-value is
brittle as the state is not idempotent: the host system counter is still
oscillating between the attempted save and restore. Furthermore, VMMs
may wish to transparently live migrate guest VMs, meaning that they
include the elapsed time due to live migration blackout in the guest
system counter view. The VMM thread could be preempted for any number of
reasons (scheduler, L0 hypervisor under nested) between the time that
it calculates the desired guest counter value and when KVM actually sets
this counter state.
Despite the value-based interface that we present to userspace, KVM
actually has idempotent guest controls by way of system counter offsets.
We can avoid all of the issues associated with a value-based interface
by abstracting these offset controls in new ioctls. This series
introduces new vCPU device attributes to provide userspace access to the
vCPU's system counter offset.
Patch 1 addresses a possible race in KVM_GET_CLOCK where
use_master_clock is read outside of the pvclock_gtod_sync_lock.
Patch 2 adopts Paolo's suggestion, augmenting the KVM_{GET,SET}_CLOCK
ioctls to provide userspace with a (host_tsc, realtime) instant. This is
essential for a VMM to perform precise migration of the guest's system
counters.
Patches 3-4 are some preparatory changes for exposing the TSC offset to
userspace. Patch 5 provides a vCPU attribute to provide userspace access
to the TSC offset.
Patches 6-7 implement a test for the new additions to
KVM_{GET,SET}_CLOCK.
Patch 8 fixes some assertions in the kvm device attribute helpers.
Patches 9-10 implement at test for the tsc offset attribute introduced in
patch 5.
Patches 11-12 lay the groundwork for patch 13, which exposes CNTVOFF_EL2
through the ONE_REG interface.
Patches 14-15 add test cases for userspace manipulation of the virtual
counter-timer.
Patches 16-17 add a vCPU attribute to adjust the host-guest offset of an
ARM vCPU, but only implements support for ECV hosts. Patches 18-19 add
support for non-ECV hosts by emulating physical counter offsetting.
Patch 20 adds test cases for adjusting the host-guest offset, and
finally patch 21 adds a test to measure the emulation overhead of
CNTPCT_EL2.
This series was tested on both an Ampere Mt. Jade and Haswell systems.
Unfortunately, the ECV portions of this series are untested, as there is
no ECV-capable hardware and the ARM fast models only partially implement
ECV.
Physical counter benchmark
--------------------------
The following data was collected by running 10000 iterations of the
benchmark test from Patch 21 on an Ampere Mt. Jade reference server, A 2S
machine with 2 80-core Ampere Altra SoCs. Measurements were collected
for both VHE and nVHE operation using the `kvm-arm.mode=` command-line
parameter.
nVHE
----
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 54ns | 148ns |
| Standard Deviation | 124ns | 122ns |
| 95th Percentile | 258ns | 348ns |
+--------------------+--------+---------+
VHE
---
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 53ns | 152ns |
| Standard Deviation | 92ns | 94ns |
| 95th Percentile | 204ns | 307ns |
+--------------------+--------+---------+
This series applies cleanly to kvm/queue at the following commit:
6cd974485e25 ("KVM: selftests: Add a test of an unbacked nested PI descriptor")
v1 -> v2:
- Reimplemented as vCPU device attributes instead of a distinct ioctl.
- Added the (realtime, host_tsc) instant support to KVM_{GET,SET}_CLOCK
- Changed the arm64 implementation to broadcast counter
offset values to all vCPUs in a guest. This upholds the
architectural expectations of a consistent counter-timer across CPUs.
- Fixed a bug with traps in VHE mode. We now configure traps on every
transition into a guest to handle differing VMs (trapped, emulated).
v2 -> v3:
- Added documentation for additions to KVM_{GET,SET}_CLOCK
- Added documentation for all new vCPU attributes
- Added documentation for suggested algorithm to migrate a guest's
TSC(s)
- Bug fixes throughout series
- Rename KVM_CLOCK_REAL_TIME -> KVM_CLOCK_REALTIME
v3 -> v4:
- Added patch to address incorrect device helper assertions (Drew)
- Carried Drew's r-b tags where appropriate
- x86 selftest cleanup
- Removed stale kvm_timer_init_vhe() function
- Removed unnecessary GUEST_DONE() from selftests
v4 -> v5:
- Fix typo in TSC migration algorithm
- Carry more of Drew's r-b tags
- clean up run loop logic in counter emulation benchmark (missed from
Drew's comments on v3)
v5 -> v6:
- Add fix for race in KVM_GET_CLOCK (Sean)
- Fix 32-bit build issues in series + use of uninitialized host tsc
value (Sean)
- General style cleanups
- Rework ARM virtual counter offsetting to match guest behavior. Use
the ONE_REG interface instead of a VM attribute (Marc)
- Maintain a single host-guest counter offset, which applies to both
physical and virtual counters
- Dropped some of Drew's r-b tags due to nontrivial patch changes
(sorry for the churn!)
v1: https://lore.kernel.org/kvm/20210608214742.1897483-1-oupton@google.com/
v2: https://lore.kernel.org/r/20210716212629.2232756-1-oupton@google.com
v3: https://lore.kernel.org/r/20210719184949.1385910-1-oupton@google.com
v4: https://lore.kernel.org/r/20210729001012.70394-1-oupton@google.com
v5: https://lore.kernel.org/r/20210729173300.181775-1-oupton@google.com
Oliver Upton (21):
KVM: x86: Fix potential race in KVM_GET_CLOCK
KVM: x86: Report host tsc and realtime values in KVM_GET_CLOCK
KVM: x86: Take the pvclock sync lock behind the tsc_write_lock
KVM: x86: Refactor tsc synchronization code
KVM: x86: Expose TSC offset controls to userspace
tools: arch: x86: pull in pvclock headers
selftests: KVM: Add test for KVM_{GET,SET}_CLOCK
selftests: KVM: Fix kvm device helper ioctl assertions
selftests: KVM: Add helpers for vCPU device attributes
selftests: KVM: Introduce system counter offset test
KVM: arm64: Refactor update_vtimer_cntvoff()
KVM: arm64: Separate guest/host counter offset values
KVM: arm64: Allow userspace to configure a vCPU's virtual offset
selftests: KVM: Add helper to check for register presence
selftests: KVM: Add support for aarch64 to system_counter_offset_test
arm64: cpufeature: Enumerate support for Enhanced Counter
Virtualization
KVM: arm64: Allow userspace to configure a guest's counter-timer
offset
KVM: arm64: Configure timer traps in vcpu_load() for VHE
KVM: arm64: Emulate physical counter offsetting on non-ECV systems
selftests: KVM: Test physical counter offsetting
selftests: KVM: Add counter emulation benchmark
Documentation/virt/kvm/api.rst | 52 ++-
Documentation/virt/kvm/devices/vcpu.rst | 85 ++++
Documentation/virt/kvm/locking.rst | 11 +
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 5 +
arch/arm64/include/uapi/asm/kvm.h | 2 +
arch/arm64/kernel/cpufeature.c | 10 +
arch/arm64/kvm/arch_timer.c | 224 ++++++++++-
arch/arm64/kvm/arm.c | 4 +-
arch/arm64/kvm/guest.c | 6 +-
arch/arm64/kvm/hyp/include/hyp/switch.h | 29 ++
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 +
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 16 +-
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
arch/arm64/tools/cpucaps | 1 +
arch/x86/include/asm/kvm_host.h | 4 +
arch/x86/include/uapi/asm/kvm.h | 4 +
arch/x86/kvm/x86.c | 364 +++++++++++++-----
include/clocksource/arm_arch_timer.h | 1 +
include/kvm/arm_arch_timer.h | 6 +-
include/uapi/linux/kvm.h | 7 +-
tools/arch/x86/include/asm/pvclock-abi.h | 48 +++
tools/arch/x86/include/asm/pvclock.h | 103 +++++
tools/testing/selftests/kvm/.gitignore | 3 +
tools/testing/selftests/kvm/Makefile | 4 +
.../kvm/aarch64/counter_emulation_benchmark.c | 207 ++++++++++
.../selftests/kvm/include/aarch64/processor.h | 24 ++
.../testing/selftests/kvm/include/kvm_util.h | 13 +
tools/testing/selftests/kvm/lib/kvm_util.c | 63 ++-
.../kvm/system_counter_offset_test.c | 211 ++++++++++
.../selftests/kvm/x86_64/kvm_clock_test.c | 204 ++++++++++
31 files changed, 1581 insertions(+), 143 deletions(-)
create mode 100644 tools/arch/x86/include/asm/pvclock-abi.h
create mode 100644 tools/arch/x86/include/asm/pvclock.h
create mode 100644 tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c
create mode 100644 tools/testing/selftests/kvm/system_counter_offset_test.c
create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_clock_test.c
--
2.32.0.605.g8dce9f2422-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-04 09:01:01
Handling the migration of TSCs correctly is difficult, in part because
Linux does not provide userspace with the ability to retrieve a (TSC,
realtime) clock pair for a single instant in time. In lieu of a more
convenient facility, KVM can report similar information in the kvm_clock
structure.
Provide userspace with a host TSC & realtime pair iff the realtime clock
is based on the TSC. If userspace provides KVM_SET_CLOCK with a valid
realtime value, advance the KVM clock by the amount of elapsed time. Do
not step the KVM clock backwards, though, as it is a monotonic
oscillator.
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/api.rst | 42 ++++++++---
arch/x86/include/asm/kvm_host.h | 3 +
arch/x86/kvm/x86.c | 127 ++++++++++++++++++--------------
include/uapi/linux/kvm.h | 7 +-
4 files changed, 112 insertions(+), 67 deletions(-)
@@ -993,20 +993,34 @@ such as migration. When KVM_CAP_ADJUST_CLOCK is passed to KVM_CHECK_EXTENSION, it returns the set of bits that KVM can return in struct kvm_clock_data's flag member.-The only flag defined now is KVM_CLOCK_TSC_STABLE. If set, the returned-value is the exact kvmclock value seen by all VCPUs at the instant-when KVM_GET_CLOCK was called. If clear, the returned value is simply-CLOCK_MONOTONIC plus a constant offset; the offset can be modified-with KVM_SET_CLOCK. KVM will try to make all VCPUs follow this clock,-but the exact value read by each VCPU could differ, because the host-TSC is not stable.+FLAGS:++KVM_CLOCK_TSC_STABLE. If set, the returned value is the exact kvmclock+value seen by all VCPUs at the instant when KVM_GET_CLOCK was called.+If clear, the returned value is simply CLOCK_MONOTONIC plus a constant+offset; the offset can be modified with KVM_SET_CLOCK. KVM will try+to make all VCPUs follow this clock, but the exact value read by each+VCPU could differ, because the host TSC is not stable.++KVM_CLOCK_REALTIME. If set, the `realtime` field in the kvm_clock_data+structure is populated with the value of the host's real time+clocksource at the instant when KVM_GET_CLOCK was called. If clear,+the `realtime` field does not contain a value.++KVM_CLOCK_HOST_TSC. If set, the `host_tsc` field in the kvm_clock_data+structure is populated with the value of the host's timestamp counter (TSC)+at the instant when KVM_GET_CLOCK was called. If clear, the `host_tsc` field+does not contain a value. :: struct kvm_clock_data { __u64 clock; /* kvmclock current value */ __u32 flags;- __u32 pad[9];+ __u32 pad0;+ __u64 realtime;+ __u64 host_tsc;+ __u32 pad[4]; };
@@ -1023,12 +1037,22 @@ Sets the current timestamp of kvmclock to the value specified in its parameter. In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios such as migration.+FLAGS:++KVM_CLOCK_REALTIME. If set, KVM will compare the value of the `realtime` field+with the value of the host's real time clocksource at the instant when+KVM_SET_CLOCK was called. The difference in elapsed time is added to the final+kvmclock value that will be provided to guests.+ :: struct kvm_clock_data { __u64 clock; /* kvmclock current value */ __u32 flags;- __u32 pad[9];+ __u32 pad0;+ __u64 realtime;+ __u64 host_tsc;+ __u32 pad[4]; };
@@ -4047,7 +4057,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)r=KVM_SYNC_X86_VALID_FIELDS;break;caseKVM_CAP_ADJUST_CLOCK:-r=KVM_CLOCK_TSC_STABLE;+r=KVM_CLOCK_VALID_FLAGS;break;caseKVM_CAP_X86_DISABLE_EXITS:r|=KVM_X86_DISABLE_EXITS_HLT|KVM_X86_DISABLE_EXITS_PAUSE|
@@ -5834,6 +5844,60 @@ int kvm_arch_pm_notifier(struct kvm *kvm, unsigned long state)}#endif /* CONFIG_HAVE_KVM_PM_NOTIFIER */+staticintkvm_vm_ioctl_get_clock(structkvm*kvm,void__user*argp)+{+structkvm_clock_datadata;++memset(&data,0,sizeof(data));+get_kvmclock(kvm,&data);++if(copy_to_user(argp,&data,sizeof(data)))+return-EFAULT;++return0;+}++staticintkvm_vm_ioctl_set_clock(structkvm*kvm,void__user*argp)+{+structkvm_arch*ka=&kvm->arch;+structkvm_clock_datadata;+u64now_raw_ns;++if(copy_from_user(&data,argp,sizeof(data)))+return-EFAULT;++if(data.flags&~KVM_CLOCK_REALTIME)+return-EINVAL;++/*+*TODO:userspacehastotakecareofraceswithVCPU_RUN,so+*kvm_gen_update_masterclock()canbecutdowntolocked+*pvclock_update_vm_gtod_copy().+*/+kvm_gen_update_masterclock(kvm);++spin_lock_irq(&ka->pvclock_gtod_sync_lock);+if(data.flags&KVM_CLOCK_REALTIME){+u64now_real_ns=ktime_get_real_ns();++/*+*Avoidsteppingthekvmclockbackwards.+*/+if(now_real_ns>data.realtime)+data.clock+=now_real_ns-data.realtime;+}++if(ka->use_master_clock)+now_raw_ns=ka->master_kernel_ns;+else+now_raw_ns=get_kvmclock_base_ns();+ka->kvmclock_offset=data.clock-now_raw_ns;+spin_unlock_irq(&ka->pvclock_gtod_sync_lock);++kvm_make_all_cpus_request(kvm,KVM_REQ_CLOCK_UPDATE);+return0;+}+longkvm_arch_vm_ioctl(structfile*filp,unsignedintioctl,unsignedlongarg){
@@ -6077,63 +6141,12 @@ long kvm_arch_vm_ioctl(struct file *filp,break;}#endif-caseKVM_SET_CLOCK:{-structkvm_arch*ka=&kvm->arch;-structkvm_clock_datauser_ns;-u64now_ns;--r=-EFAULT;-if(copy_from_user(&user_ns,argp,sizeof(user_ns)))-gotoout;--r=-EINVAL;-if(user_ns.flags)-gotoout;--r=0;-/*-*TODO:userspacehastotakecareofraceswithVCPU_RUN,so-*kvm_gen_update_masterclock()canbecutdowntolocked-*pvclock_update_vm_gtod_copy().-*/-kvm_gen_update_masterclock(kvm);--/*-*Thispairswithkvm_guest_time_update():whenmasterclockis-*inuse,weusemaster_kernel_ns+kvmclock_offsettoset-*unsigned'system_time'soifweuseget_kvmclock_ns()(which-*isslightlyahead)hereweriskgoingnegativeonunsigned-*'system_time'when'user_ns.clock'isverysmall.-*/-spin_lock_irq(&ka->pvclock_gtod_sync_lock);-if(kvm->arch.use_master_clock)-now_ns=ka->master_kernel_ns;-else-now_ns=get_kvmclock_base_ns();-ka->kvmclock_offset=user_ns.clock-now_ns;-spin_unlock_irq(&ka->pvclock_gtod_sync_lock);--kvm_make_all_cpus_request(kvm,KVM_REQ_CLOCK_UPDATE);+caseKVM_SET_CLOCK:+r=kvm_vm_ioctl_set_clock(kvm,argp);break;-}-caseKVM_GET_CLOCK:{-structkvm_clock_datauser_ns;--/*-*ZeroflagsasitisaccessedRMW,leaveeverythingelse-*uninitializedasclockisalwayswrittenandnootherfields-*areconsumed.-*/-user_ns.flags=0;-get_kvmclock(kvm,&user_ns);-memset(&user_ns.pad,0,sizeof(user_ns.pad));--r=-EFAULT;-if(copy_to_user(argp,&user_ns,sizeof(user_ns)))-gotoout;-r=0;+caseKVM_GET_CLOCK:+r=kvm_vm_ioctl_get_clock(kvm,argp);break;-}caseKVM_MEMORY_ENCRYPT_OP:{r=-ENOTTY;if(kvm_x86_ops.mem_enc_op)
@@ -1223,11 +1223,16 @@ struct kvm_irqfd {/* Do not use 1, KVM_CHECK_EXTENSION returned it before we had flags. */#define KVM_CLOCK_TSC_STABLE 2+#define KVM_CLOCK_REALTIME (1 << 2)+#define KVM_CLOCK_HOST_TSC (1 << 3)structkvm_clock_data{__u64clock;__u32flags;-__u32pad[9];+__u32pad0;+__u64realtime;+__u64host_tsc;+__u32pad[4];};/* For KVM_CAP_SW_TLB */
--
2.32.0.605.g8dce9f2422-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-04 09:01:17
Refactor kvm_synchronize_tsc to make a new function that allows callers
to specify TSC parameters (offset, value, nanoseconds, etc.) explicitly
for the sake of participating in TSC synchronization.
Signed-off-by: Oliver Upton <redacted>
---
arch/x86/kvm/x86.c | 105 ++++++++++++++++++++++++++-------------------
1 file changed, 61 insertions(+), 44 deletions(-)
@@ -2443,13 +2443,71 @@ static inline bool kvm_check_tsc_unstable(void)returncheck_tsc_unstable();}+/*+*Infersattemptstosynchronizetheguest'stscfromhostwrites.Setsthe+*offsetforthevcpuandtrackstheTSCmatchinggenerationthatthevcpu+*participatesin.+*/+staticvoid__kvm_synchronize_tsc(structkvm_vcpu*vcpu,u64offset,u64tsc,+u64ns,boolmatched)+{+structkvm*kvm=vcpu->kvm;+boolalready_matched;++lockdep_assert_held(&kvm->arch.tsc_write_lock);++already_matched=+(vcpu->arch.this_tsc_generation==kvm->arch.cur_tsc_generation);++/*+*WetrackthemostrecentrecordedKHZ,writeandtimeto+*allowthematchingintervaltobeextendedateachwrite.+*/+kvm->arch.last_tsc_nsec=ns;+kvm->arch.last_tsc_write=tsc;+kvm->arch.last_tsc_khz=vcpu->arch.virtual_tsc_khz;++vcpu->arch.last_guest_tsc=tsc;++/* Keep track of which generation this VCPU has synchronized to */+vcpu->arch.this_tsc_generation=kvm->arch.cur_tsc_generation;+vcpu->arch.this_tsc_nsec=kvm->arch.cur_tsc_nsec;+vcpu->arch.this_tsc_write=kvm->arch.cur_tsc_write;++kvm_vcpu_write_tsc_offset(vcpu,offset);++if(!matched){+/*+*WesplitperiodsofmatchedTSCwritesintogenerations.+*Foreachgeneration,wetracktheoriginalmeasured+*nanosecondtime,offset,andwrite,soifTSCsarein+*sync,wecanmatchexactoffset,andifnot,wecanmatch+*exactsoftwarecomputationincompute_guest_tsc()+*+*Thesevaluesaretrackedinkvm->arch.cur_xxxvariables.+*/+kvm->arch.cur_tsc_generation++;+kvm->arch.cur_tsc_nsec=ns;+kvm->arch.cur_tsc_write=tsc;+kvm->arch.cur_tsc_offset=offset;++spin_lock(&kvm->arch.pvclock_gtod_sync_lock);+kvm->arch.nr_vcpus_matched_tsc=0;+}elseif(!already_matched){+spin_lock(&kvm->arch.pvclock_gtod_sync_lock);+kvm->arch.nr_vcpus_matched_tsc++;+}++kvm_track_tsc_matching(vcpu);+spin_unlock(&kvm->arch.pvclock_gtod_sync_lock);+}+staticvoidkvm_synchronize_tsc(structkvm_vcpu*vcpu,u64data){structkvm*kvm=vcpu->kvm;u64offset,ns,elapsed;unsignedlongflags;-boolmatched;-boolalready_matched;+boolmatched=false;boolsynchronizing=false;raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock,flags);
@@ -2495,50 +2553,9 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 data)offset=kvm_compute_l1_tsc_offset(vcpu,data);}matched=true;-already_matched=(vcpu->arch.this_tsc_generation==kvm->arch.cur_tsc_generation);-}else{-/*-*WesplitperiodsofmatchedTSCwritesintogenerations.-*Foreachgeneration,wetracktheoriginalmeasured-*nanosecondtime,offset,andwrite,soifTSCsarein-*sync,wecanmatchexactoffset,andifnot,wecanmatch-*exactsoftwarecomputationincompute_guest_tsc()-*-*Thesevaluesaretrackedinkvm->arch.cur_xxxvariables.-*/-kvm->arch.cur_tsc_generation++;-kvm->arch.cur_tsc_nsec=ns;-kvm->arch.cur_tsc_write=data;-kvm->arch.cur_tsc_offset=offset;-matched=false;}-/*-*WealsotrackthmostrecentrecordedKHZ,writeandtimeto-*allowthematchingintervaltobeextendedateachwrite.-*/-kvm->arch.last_tsc_nsec=ns;-kvm->arch.last_tsc_write=data;-kvm->arch.last_tsc_khz=vcpu->arch.virtual_tsc_khz;--vcpu->arch.last_guest_tsc=data;--/* Keep track of which generation this VCPU has synchronized to */-vcpu->arch.this_tsc_generation=kvm->arch.cur_tsc_generation;-vcpu->arch.this_tsc_nsec=kvm->arch.cur_tsc_nsec;-vcpu->arch.this_tsc_write=kvm->arch.cur_tsc_write;--kvm_vcpu_write_tsc_offset(vcpu,offset);--spin_lock_irqsave(&kvm->arch.pvclock_gtod_sync_lock,flags);-if(!matched){-kvm->arch.nr_vcpus_matched_tsc=0;-}elseif(!already_matched){-kvm->arch.nr_vcpus_matched_tsc++;-}--kvm_track_tsc_matching(vcpu);-spin_unlock_irqrestore(&kvm->arch.pvclock_gtod_sync_lock,flags);+__kvm_synchronize_tsc(vcpu,offset,data,ns,matched);raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock,flags);}
--
2.32.0.605.g8dce9f2422-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-04 09:01:22
Sean noticed that KVM_GET_CLOCK was checking kvm_arch.use_master_clock
outside of the pvclock sync lock. This is problematic, as the clock
value written to the user may or may not actually correspond to a stable
TSC.
Fix the race by populating the entire kvm_clock_data structure behind
the pvclock_gtod_sync_lock.
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Oliver Upton <redacted>
---
arch/x86/kvm/x86.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
From: Oliver Upton <hidden> Date: 2021-08-04 09:01:28
To date, VMM-directed TSC synchronization and migration has been a bit
messy. KVM has some baked-in heuristics around TSC writes to infer if
the VMM is attempting to synchronize. This is problematic, as it depends
on host userspace writing to the guest's TSC within 1 second of the last
write.
A much cleaner approach to configuring the guest's views of the TSC is to
simply migrate the TSC offset for every vCPU. Offsets are idempotent,
and thus not subject to change depending on when the VMM actually
reads/writes values from/to KVM. The VMM can then read the TSC once with
KVM_GET_CLOCK to capture a (realtime, host_tsc) pair at the instant when
the guest is paused.
Cc: David Matlack <dmatlack@google.com>
Cc: Sean Christopherson <seanjc@google.com>
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/devices/vcpu.rst | 57 +++++++++++++
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/include/uapi/asm/kvm.h | 4 +
arch/x86/kvm/x86.c | 109 ++++++++++++++++++++++++
4 files changed, 171 insertions(+)
@@ -161,3 +161,60 @@ Specifies the base address of the stolen time structure for this VCPU. The base address must be 64 byte aligned and exist within a valid guest memory region. See Documentation/virt/kvm/arm/pvtime.rst for more information including the layout of the stolen time structure.++4. GROUP: KVM_VCPU_TSC_CTRL+===========================++:Architectures: x86++4.1 ATTRIBUTE: KVM_VCPU_TSC_OFFSET++:Parameters: 64-bit unsigned TSC offset++Returns:++ ======= ======================================+ -EFAULT Error reading/writing the provided+ parameter address.+ -ENXIO Attribute not supported+ ======= ======================================++Specifies the guest's TSC offset relative to the host's TSC. The guest's+TSC is then derived by the following equation:++ guest_tsc = host_tsc + KVM_VCPU_TSC_OFFSET++This attribute is useful for the precise migration of a guest's TSC. The+following describes a possible algorithm to use for the migration of a+guest's TSC:++From the source VMM process:++1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (t_0),+ kvmclock nanoseconds (k_0), and realtime nanoseconds (r_0).++2. Read the KVM_VCPU_TSC_OFFSET attribute for every vCPU to record the+ guest TSC offset (off_n).++3. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the+ guest's TSC (freq).++From the destination VMM process:++4. Invoke the KVM_SET_CLOCK ioctl, providing the kvmclock nanoseconds+ (k_0) and realtime nanoseconds (r_0) in their respective fields.+ Ensure that the KVM_CLOCK_REALTIME flag is set in the provided+ structure. KVM will advance the VM's kvmclock to account for elapsed+ time since recording the clock values.++5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (t_1) and+ kvmclock nanoseconds (k_1).++6. Adjust the guest TSC offsets for every vCPU to account for (1) time+ elapsed since recording state and (2) difference in TSCs between the+ source and destination machine:++ new_off_n = t_0 + off_n + (k_1 - k_0) * freq - t_1++7. Write the KVM_VCPU_TSC_OFFSET attribute for every vCPU with the+ respective value derived in the previous step.
From: Oliver Upton <hidden> Date: 2021-08-04 09:01:34
A later change requires that the pvclock sync lock be taken while
holding the tsc_write_lock. Change the locking in kvm_synchronize_tsc()
to align with the requirement to isolate the locking change to its own
commit.
Cc: Sean Christopherson <seanjc@google.com>
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/locking.rst | 11 +++++++++++
arch/x86/kvm/x86.c | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
@@ -36,6 +36,9 @@ On x86: holding kvm->arch.mmu_lock (typically with ``read_lock``, otherwise there's no need to take kvm->arch.tdp_mmu_pages_lock at all).+- kvm->arch.tsc_write_lock is taken outside+ kvm->arch.pvclock_gtod_sync_lock+ Everything else is a leaf: no other lock is taken inside the critical sections.
@@ -222,6 +225,14 @@ time it will be set using the Dirty tracking mechanism described above.:Comment: 'raw' because hardware enabling/disabling must be atomic /wrt migration.+:Name: kvm_arch::pvclock_gtod_sync_lock+:Type: raw_spinlock_t+:Arch: x86+:Protects: kvm_arch::{cur_tsc_generation,cur_tsc_nsec,cur_tsc_write,+ cur_tsc_offset,nr_vcpus_matched_tsc}+:Comment: 'raw' because updating the kvm master clock must not be+ preempted.+:Name: kvm_arch::tsc_write_lock:Type: raw_spinlock:Arch: x86
From: Oliver Upton <hidden> Date: 2021-08-04 09:01:45
Copy over approximately clean versions of the pvclock headers into
tools. Reconcile headers/symbols missing in tools that are unneeded.
Signed-off-by: Oliver Upton <redacted>
---
tools/arch/x86/include/asm/pvclock-abi.h | 48 +++++++++++
tools/arch/x86/include/asm/pvclock.h | 103 +++++++++++++++++++++++
2 files changed, 151 insertions(+)
create mode 100644 tools/arch/x86/include/asm/pvclock-abi.h
create mode 100644 tools/arch/x86/include/asm/pvclock.h
@@ -0,0 +1,103 @@+/* SPDX-License-Identifier: GPL-2.0 */+#ifndef _ASM_X86_PVCLOCK_H+#define _ASM_X86_PVCLOCK_H++#include<asm/barrier.h>+#include<asm/pvclock-abi.h>++/* some helper functions for xen and kvm pv clock sources */+u64pvclock_clocksource_read(structpvclock_vcpu_time_info*src);+u8pvclock_read_flags(structpvclock_vcpu_time_info*src);+voidpvclock_set_flags(u8flags);+unsignedlongpvclock_tsc_khz(structpvclock_vcpu_time_info*src);+voidpvclock_resume(void);++voidpvclock_touch_watchdogs(void);++static__always_inline+unsignedpvclock_read_begin(conststructpvclock_vcpu_time_info*src)+{+unsignedversion=src->version&~1;+/* Make sure that the version is read before the data. */+rmb();+returnversion;+}++static__always_inline+boolpvclock_read_retry(conststructpvclock_vcpu_time_info*src,+unsignedversion)+{+/* Make sure that the version is re-read after the data. */+rmb();+returnversion!=src->version;+}++/*+*Scalea64-bitdeltabyscalingandmultiplyingbya32-bitfraction,+*yieldinga64-bitresult.+*/+staticinlineu64pvclock_scale_delta(u64delta,u32mul_frac,intshift)+{+u64product;+#ifdef __i386__+u32tmp1,tmp2;+#else+unsignedlongtmp;+#endif++if(shift<0)+delta>>=-shift;+else+delta<<=shift;++#ifdef __i386__+__asm__(+"mul %5 ; "+"mov %4,%%eax ; "+"mov %%edx,%4 ; "+"mul %5 ; "+"xor %5,%5 ; "+"add %4,%%eax ; "+"adc %5,%%edx ; "+:"=A"(product),"=r"(tmp1),"=r"(tmp2)+:"a"((u32)delta),"1"((u32)(delta>>32)),"2"(mul_frac));+#elif defined(__x86_64__)+__asm__(+"mulq %[mul_frac] ; shrd $32, %[hi], %[lo]"+:[lo]"=a"(product),+[hi]"=d"(tmp)+:"0"(delta),+[mul_frac]"rm"((u64)mul_frac));+#else+#error implement me!+#endif++returnproduct;+}++static__always_inline+u64__pvclock_read_cycles(conststructpvclock_vcpu_time_info*src,u64tsc)+{+u64delta=tsc-src->tsc_timestamp;+u64offset=pvclock_scale_delta(delta,src->tsc_to_system_mul,+src->tsc_shift);+returnsrc->system_time+offset;+}++structpvclock_vsyscall_time_info{+structpvclock_vcpu_time_infopvti;+}__attribute__((__aligned__(64)));++#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)++#ifdef CONFIG_PARAVIRT_CLOCK+voidpvclock_set_pvti_cpu0_va(structpvclock_vsyscall_time_info*pvti);+structpvclock_vsyscall_time_info*pvclock_get_pvti_cpu0_va(void);+#else+staticinlinestructpvclock_vsyscall_time_info*pvclock_get_pvti_cpu0_va(void)+{+returnNULL;+}+#endif++#endif /* _ASM_X86_PVCLOCK_H */
--
2.32.0.605.g8dce9f2422-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-04 09:02:08
Add a selftest for the new KVM clock UAPI that was introduced. Ensure
that the KVM clock is consistent between userspace and the guest, and
that the difference in realtime will only ever cause the KVM clock to
advance forward.
Cc: Andrew Jones <redacted>
Signed-off-by: Oliver Upton <redacted>
---
tools/testing/selftests/kvm/.gitignore | 1 +
tools/testing/selftests/kvm/Makefile | 1 +
.../testing/selftests/kvm/include/kvm_util.h | 2 +
.../selftests/kvm/x86_64/kvm_clock_test.c | 204 ++++++++++++++++++
4 files changed, 208 insertions(+)
create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_clock_test.c
From: Oliver Upton <hidden> Date: 2021-08-04 09:02:53
The KVM_CREATE_DEVICE and KVM_{GET,SET}_DEVICE_ATTR ioctls are defined
to return a value of zero on success. As such, tighten the assertions in
the helper functions to only pass if the return code is zero.
Suggested-by: Andrew Jones <redacted>
Reviewed-by: Andrew Jones <redacted>
Signed-off-by: Oliver Upton <redacted>
---
tools/testing/selftests/kvm/lib/kvm_util.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
From: Oliver Upton <hidden> Date: 2021-08-04 09:03:55
vCPU file descriptors are abstracted away from test code in KVM
selftests, meaning that tests cannot directly access a vCPU's device
attributes. Add helpers that tests can use to get at vCPU device
attributes.
Reviewed-by: Andrew Jones <redacted>
Signed-off-by: Oliver Upton <redacted>
---
.../testing/selftests/kvm/include/kvm_util.h | 9 +++++
tools/testing/selftests/kvm/lib/kvm_util.c | 38 +++++++++++++++++++
2 files changed, 47 insertions(+)
From: Oliver Upton <hidden> Date: 2021-08-04 09:04:48
Introduce a KVM selftest to verify that userspace manipulation of the
TSC (via the new vCPU attribute) results in the correct behavior within
the guest.
Reviewed-by: Andrew Jones <redacted>
Signed-off-by: Oliver Upton <redacted>
---
tools/testing/selftests/kvm/.gitignore | 1 +
tools/testing/selftests/kvm/Makefile | 1 +
.../kvm/system_counter_offset_test.c | 132 ++++++++++++++++++
3 files changed, 134 insertions(+)
create mode 100644 tools/testing/selftests/kvm/system_counter_offset_test.c
From: Oliver Upton <hidden> Date: 2021-08-04 09:05:30
Make the implementation of update_vtimer_cntvoff() generic w.r.t. guest
timer context and spin off into a new helper method for later use.
Require callers of this new helper method to grab the kvm lock
beforehand.
No functional change intended.
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/kvm/arch_timer.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
@@ -747,22 +747,32 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)return0;}-/* Make the updates of cntvoff for all vtimer contexts atomic */-staticvoidupdate_vtimer_cntvoff(structkvm_vcpu*vcpu,u64cntvoff)+/* Make offset updates for all timer contexts atomic */+staticvoidupdate_timer_offset(structkvm_vcpu*vcpu,+enumkvm_arch_timerstimer,u64offset){inti;structkvm*kvm=vcpu->kvm;structkvm_vcpu*tmp;-mutex_lock(&kvm->lock);+lockdep_assert_held(&kvm->lock);+kvm_for_each_vcpu(i,tmp,kvm)-timer_set_offset(vcpu_vtimer(tmp),cntvoff);+timer_set_offset(vcpu_get_timer(tmp,timer),offset);/**Whencalledfromthevcpucreatepath,theCPUbeingcreatedisnot*includedintheloopabove,sowejustsetithereaswell.*/-timer_set_offset(vcpu_vtimer(vcpu),cntvoff);+timer_set_offset(vcpu_get_timer(vcpu,timer),offset);+}++staticvoidupdate_vtimer_cntvoff(structkvm_vcpu*vcpu,u64cntvoff)+{+structkvm*kvm=vcpu->kvm;++mutex_lock(&kvm->lock);+update_timer_offset(vcpu,TIMER_VTIMER,cntvoff);mutex_unlock(&kvm->lock);}
--
2.32.0.605.g8dce9f2422-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-04 09:06:37
In some instances, a VMM may want to update the guest's counter-timer
offset in a transparent manner, meaning that changes to the hardware
value do not affect the synthetic register presented to the guest or the
VMM through said guest's architectural state. Lay the groundwork to
separate guest offset register writes from the hardware values utilized
by KVM.
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/kvm/arch_timer.c | 48 ++++++++++++++++++++++++++++++++----
include/kvm/arm_arch_timer.h | 3 +++
2 files changed, 46 insertions(+), 5 deletions(-)
@@ -749,7 +779,8 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)/* Make offset updates for all timer contexts atomic */staticvoidupdate_timer_offset(structkvm_vcpu*vcpu,-enumkvm_arch_timerstimer,u64offset)+enumkvm_arch_timerstimer,u64offset,+boolguest_visible){inti;structkvm*kvm=vcpu->kvm;
@@ -42,6 +42,9 @@ struct arch_timer_context {/* Duplicated state from arch_timer.c for convenience */u32host_timer_irq;u32host_timer_irq_flags;++/* offset relative to the host's physical counter-timer */+u64host_offset;};structtimer_map{
--
2.32.0.605.g8dce9f2422-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-04 09:07:25
Allow userspace to access the guest's virtual counter-timer offset
through the ONE_REG interface. The value read or written is defined to
be an offset from the guest's physical counter-timer. Add some
documentation to clarify how a VMM should use this and the existing
CNTVCT_EL0.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/api.rst | 10 ++++++++++
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 11 +++++++++++
arch/arm64/kvm/guest.c | 6 +++++-
include/kvm/arm_arch_timer.h | 1 +
5 files changed, 28 insertions(+), 1 deletion(-)
@@ -2487,6 +2487,16 @@ arm64 system registers have the following id bit patterns:: derived from the register encoding for CNTV_CVAL_EL0. As this is API, it must remain this way.+..warning::++ The value of KVM_REG_ARM_TIMER_OFFSET is defined as an offset from+ the guest's view of the physical counter-timer.++ Userspace should use either KVM_REG_ARM_TIMER_OFFSET or+ KVM_REG_ARM_TIMER_CVAL to pause and resume a guest's virtual+ counter-timer. Mixed use of these registers could result in an+ unpredictable guest counter value.+ arm64 firmware pseudo-registers have the following bit pattern:: 0x6030 0000 0014 <regno:16>
From: Oliver Upton <hidden> Date: 2021-08-04 09:08:28
The KVM_GET_REG_LIST vCPU ioctl returns a list of supported registers
for a given vCPU. Add a helper to check if a register exists in the list
of supported registers.
Signed-off-by: Oliver Upton <redacted>
---
.../testing/selftests/kvm/include/kvm_util.h | 2 ++
tools/testing/selftests/kvm/lib/kvm_util.c | 19 +++++++++++++++++++
2 files changed, 21 insertions(+)
From: Oliver Upton <hidden> Date: 2021-08-04 09:09:40
KVM/arm64 now allows userspace to adjust the guest virtual counter-timer
via a vCPU register. Test that changes to the virtual counter-timer
offset result in the correct view being presented to the guest.
Reviewed-by: Andrew Jones <redacted>
Signed-off-by: Oliver Upton <redacted>
---
tools/testing/selftests/kvm/Makefile | 1 +
.../selftests/kvm/include/aarch64/processor.h | 12 ++++
.../kvm/system_counter_offset_test.c | 56 ++++++++++++++++++-
3 files changed, 68 insertions(+), 1 deletion(-)
From: Oliver Upton <hidden> Date: 2021-08-04 09:10:53
Introduce a new cpucap to indicate if the system supports full enhanced
counter virtualization (i.e. ID_AA64MMFR0_EL1.ECV==0x2).
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/include/asm/sysreg.h | 2 ++
arch/arm64/kernel/cpufeature.c | 10 ++++++++++
arch/arm64/tools/cpucaps | 1 +
3 files changed, 13 insertions(+)
From: Oliver Upton <hidden> Date: 2021-08-04 09:11:47
Presently, KVM provides no facilities for correctly migrating a guest
that depends on the physical counter-timer. Whie most guests (barring
NV, of course) should not depend on the physical counter-timer, an
operator may wish to provide a consistent view of the physical
counter-timer across migrations.
Provide userspace with a new vCPU attribute to modify the guest
counter-timer offset. Unlike KVM_REG_ARM_TIMER_OFFSET, this attribute is
hidden from the guest's architectural state. The value offsets *both*
the virtual and physical counter-timer views for the guest. Only support
this attribute on ECV systems as ECV is required for hardware offsetting
of the physical counter-timer.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/devices/vcpu.rst | 28 ++++++
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 2 +
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 122 +++++++++++++++++++++++-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 ++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 5 +
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
include/clocksource/arm_arch_timer.h | 1 +
9 files changed, 169 insertions(+), 3 deletions(-)
@@ -139,6 +139,34 @@ configured values on other VCPUs. Userspace should configure the interrupt numbers on at least one VCPU after creating all VCPUs and before running any VCPUs.+2.2. ATTRIBUTE: KVM_ARM_VCPU_TIMER_OFFSET+-----------------------------------------++:Parameters: in kvm_device_attr.addr the address for the timer offset is a+ pointer to a __u64++Returns:++ ======= ==================================+ -EFAULT Error reading/writing the provided+ parameter address+ -ENXIO Timer offsetting not implemented+ ======= ==================================++Specifies the guest's counter-timer offset from the host's virtual counter.+The guest's physical counter value is then derived by the following+equation:++ guest_cntpct = host_cntvct - KVM_ARM_VCPU_TIMER_OFFSET++The guest's virtual counter value is derived by the following equation:++ guest_cntvct = host_cntvct - KVM_REG_ARM_TIMER_OFFSET+- KVM_ARM_VCPU_TIMER_OFFSET++KVM does not allow the use of varying offset values for different vCPUs;+the last written offset value will be broadcasted to all vCPUs in a VM.+3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL ==================================
From: Oliver Upton <hidden> Date: 2021-08-04 09:13:30
In preparation for emulated physical counter-timer offsetting, configure
traps on every vcpu_load() for VHE systems. As before, these trap
settings do not affect host userspace, and are only active for the
guest.
Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/kvm/arch_timer.c | 10 +++++++---
arch/arm64/kvm/arm.c | 4 +---
include/kvm/arm_arch_timer.h | 2 --
3 files changed, 8 insertions(+), 8 deletions(-)
@@ -1383,12 +1387,12 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)}/*-*OnVHEsystem,weonlyneedtoconfiguretheEL2timertrapregisteronce,-*notforeveryworldswitch.+*OnVHEsystem,weonlyneedtoconfiguretheEL2timertrapregisteron+*vcpu_load(),butnoteveryworldswitchintotheguest.*ThehostkernelrunsatEL2withHCR_EL2.TGE==1,*andthismakesthosebitshavenoeffectforthehostkernelexecution.*/-voidkvm_timer_init_vhe(void)+staticvoidkvm_timer_enable_traps_vhe(void){/* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */u32cnthctl_shift=10;
From: Oliver Upton <hidden> Date: 2021-08-04 09:14:37
Unfortunately, ECV hasn't yet arrived in any tangible hardware. At the
same time, controlling the guest view of the physical counter-timer is
useful. Support guest counter-timer offsetting on non-ECV systems by
trapping guest accesses to the physical counter-timer. Emulate reads of
the physical counter in the fast exit path.
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/include/asm/sysreg.h | 1 +
arch/arm64/kvm/arch_timer.c | 53 +++++++++++++++----------
arch/arm64/kvm/hyp/include/hyp/switch.h | 29 ++++++++++++++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 11 ++++-
4 files changed, 70 insertions(+), 24 deletions(-)
@@ -1392,22 +1403,29 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)*ThehostkernelrunsatEL2withHCR_EL2.TGE==1,*andthismakesthosebitshavenoeffectforthehostkernelexecution.*/-staticvoidkvm_timer_enable_traps_vhe(void)+staticvoidkvm_timer_enable_traps_vhe(structkvm_vcpu*vcpu){/* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */u32cnthctl_shift=10;-u64val;+u64val,mask;++mask=CNTHCTL_EL1PCEN<<cnthctl_shift;+mask|=CNTHCTL_EL1PCTEN<<cnthctl_shift;-/*-*VHEsystemsallowtheguestdirectaccesstotheEL1physical-*timer/counter.-*/val=read_sysreg(cnthctl_el2);-val|=(CNTHCTL_EL1PCEN<<cnthctl_shift);-val|=(CNTHCTL_EL1PCTEN<<cnthctl_shift);if(cpus_have_const_cap(ARM64_ECV))val|=CNTHCTL_ECV;++/*+*VHEsystemsallowtheguestdirectaccesstotheEL1physical+*timer/counterifoffsettingisn'trequestedonanon-ECVsystem.+*/+if(ptimer_emulation_required(vcpu))+val&=~mask;+else+val|=mask;+write_sysreg(val,cnthctl_el2);}
@@ -1462,9 +1480,6 @@ static int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu,u64__user*uaddr=(u64__user*)(long)attr->addr;u64offset;-if(!cpus_have_const_cap(ARM64_ECV))-return-ENXIO;-if(get_user(offset,uaddr))return-EFAULT;
@@ -1513,9 +1528,6 @@ static int kvm_arm_timer_get_attr_offset(struct kvm_vcpu *vcpu,u64__user*uaddr=(u64__user*)(long)attr->addr;u64offset;-if(!cpus_have_const_cap(ARM64_ECV))-return-ENXIO;-offset=timer_get_offset(vcpu_ptimer(vcpu));returnput_user(offset,uaddr);}
From: Oliver Upton <hidden> Date: 2021-08-04 09:16:32
Test that userspace adjustment of the guest physical counter-timer
results in the correct view within the guest.
Cc: Andrew Jones <redacted>
Signed-off-by: Oliver Upton <redacted>
---
.../selftests/kvm/include/aarch64/processor.h | 12 +++++++
.../kvm/system_counter_offset_test.c | 31 +++++++++++++++++--
2 files changed, 40 insertions(+), 3 deletions(-)
From: Oliver Upton <hidden> Date: 2021-08-04 09:17:38
Add a test case for counter emulation on arm64. A side effect of how KVM
handles physical counter offsetting on non-ECV systems is that the
virtual counter will always hit hardware and the physical could be
emulated. Force emulation by writing a nonzero offset to the physical
counter and compare the elapsed cycles to a direct read of the hardware
register.
Reviewed-by: Ricardo Koller <redacted>
Signed-off-by: Oliver Upton <redacted>
Reviewed-by: Andrew Jones <redacted>
---
tools/testing/selftests/kvm/.gitignore | 1 +
tools/testing/selftests/kvm/Makefile | 1 +
.../kvm/aarch64/counter_emulation_benchmark.c | 207 ++++++++++++++++++
3 files changed, 209 insertions(+)
create mode 100644 tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c
@@ -0,0 +1,207 @@+// SPDX-License-Identifier: GPL-2.0+/*+*counter_emulation_benchmark.c--testtomeasuretheeffectsofcounter+*emulationonguestreadsofthephysicalcounter.+*+*Copyright(c)2021,GoogleLLC.+*/++#define _GNU_SOURCE+#include<asm/kvm.h>+#include<linux/kvm.h>+#include<stdio.h>+#include<stdint.h>+#include<stdlib.h>+#include<unistd.h>++#include"kvm_util.h"+#include"processor.h"+#include"test_util.h"++#define VCPU_ID 0++staticstructcounter_values{+uint64_tcntvct_start;+uint64_tcntpct;+uint64_tcntvct_end;+}counter_values;++staticuint64_tnr_iterations=1000;++staticvoiddo_test(void)+{+/*+*Open-codedapproachinsteadofusinghelpermethodstokeepatight+*intervalaroundthephysicalcounterread.+*/+asmvolatile("isb\n\t"+"mrs %[cntvct_start], cntvct_el0\n\t"+"isb\n\t"+"mrs %[cntpct], cntpct_el0\n\t"+"isb\n\t"+"mrs %[cntvct_end], cntvct_el0\n\t"+"isb\n\t"+:[cntvct_start]"=r"(counter_values.cntvct_start),+[cntpct]"=r"(counter_values.cntpct),+[cntvct_end]"=r"(counter_values.cntvct_end));+}++staticvoidguest_main(void)+{+inti;++for(i=0;i<nr_iterations;i++){+do_test();+GUEST_SYNC(i);+}++for(i=0;i<nr_iterations;i++){+do_test();+GUEST_SYNC(i);+}+}++staticvoidenter_guest(structkvm_vm*vm)+{+structucalluc;++vcpu_ioctl(vm,VCPU_ID,KVM_RUN,NULL);++switch(get_ucall(vm,VCPU_ID,&uc)){+caseUCALL_SYNC:+break;+caseUCALL_ABORT:+TEST_ASSERT(false,"%s at %s:%ld",(constchar*)uc.args[0],+__FILE__,uc.args[1]);+break;+default:+TEST_ASSERT(false,"unexpected exit: %s",+exit_reason_str(vcpu_state(vm,VCPU_ID)->exit_reason));+break;+}+}++staticdoublecounter_frequency(void)+{+uint32_tfreq;++asmvolatile("mrs %0, cntfrq_el0"+:"=r"(freq));++returnfreq/1000000.0;+}++staticvoidlog_csv(FILE*csv,booltrapped)+{+doublefreq=counter_frequency();++fprintf(csv,"%s,%.02f,%lu,%lu,%lu\n",+trapped?"true":"false",freq,+counter_values.cntvct_start,+counter_values.cntpct,+counter_values.cntvct_end);+}++staticdoublerun_loop(structkvm_vm*vm,FILE*csv,booltrapped)+{+doubleavg=0;+inti;++for(i=0;i<nr_iterations;i++){+uint64_tdelta;++enter_guest(vm);+sync_global_from_guest(vm,counter_values);++if(csv)+log_csv(csv,trapped);++delta=counter_values.cntvct_end-counter_values.cntvct_start;+avg=((avg*i)+delta)/(i+1);+}++returnavg;+}++staticvoidsetup_counter(structkvm_vm*vm,uint64_toffset)+{+vcpu_access_device_attr(vm,VCPU_ID,KVM_ARM_VCPU_TIMER_CTRL,+KVM_ARM_VCPU_TIMER_OFFSET,&offset,+true);+}++staticvoidrun_tests(structkvm_vm*vm,FILE*csv)+{+doubleavg_trapped,avg_native,freq;++freq=counter_frequency();++if(csv)+fputs("trapped,freq_mhz,cntvct_start,cntpct,cntvct_end\n",csv);++/* no physical offsetting; kvm allows reads of cntpct_el0 */+setup_counter(vm,0);+avg_native=run_loop(vm,csv,false);++/* force emulation of the physical counter */+setup_counter(vm,1);+avg_trapped=run_loop(vm,csv,true);++pr_info("%lu iterations: average cycles (@%.02fMHz) native: %.02f, trapped: %.02f\n",+nr_iterations,freq,avg_native,avg_trapped);+}++staticvoidusage(constchar*program_name)+{+fprintf(stderr,+"Usage: %s [-h] [-o csv_file] [-n iterations]\n"+" -h prints this message\n"+" -n number of test iterations (default: %lu)\n"+" -o csv file to write data\n",+program_name,nr_iterations);+}++intmain(intargc,char**argv)+{+structkvm_vm*vm;+FILE*csv=NULL;+intopt;++while((opt=getopt(argc,argv,"hn:o:"))!=-1){+switch(opt){+case'o':+csv=fopen(optarg,"w");+if(!csv){+fprintf(stderr,"failed to open file '%s': %d\n",+optarg,errno);+exit(1);+}+break;+case'n':+nr_iterations=strtoul(optarg,NULL,0);+break;+default:+fprintf(stderr,"unrecognized option: '-%c'\n",opt);+/* fallthrough */+case'h':+usage(argv[0]);+exit(1);+}+}++vm=vm_create_default(VCPU_ID,0,guest_main);+sync_global_to_guest(vm,nr_iterations);+ucall_init(vm,NULL);++if(_vcpu_has_device_attr(vm,VCPU_ID,KVM_ARM_VCPU_TIMER_CTRL,+KVM_ARM_VCPU_TIMER_OFFSET)){+print_skip("KVM_ARM_VCPU_TIMER_OFFSET not supported.");+exit(KSFT_SKIP);+}++run_tests(vm,csv);+kvm_vm_free(vm);++if(csv)+fclose(csv);+}
--
2.32.0.605.g8dce9f2422-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Andrew Jones <hidden> Date: 2021-08-04 09:27:38
On Wed, Aug 04, 2021 at 08:58:12AM +0000, Oliver Upton wrote:
quoted hunk
The KVM_GET_REG_LIST vCPU ioctl returns a list of supported registers
for a given vCPU. Add a helper to check if a register exists in the list
of supported registers.
Signed-off-by: Oliver Upton <redacted>
---
.../testing/selftests/kvm/include/kvm_util.h | 2 ++
tools/testing/selftests/kvm/lib/kvm_util.c | 19 +++++++++++++++++++
2 files changed, 21 insertions(+)
From: Andrew Jones <hidden> Date: 2021-08-04 09:33:43
On Wed, Aug 04, 2021 at 08:58:09AM +0000, Oliver Upton wrote:
quoted hunk
Make the implementation of update_vtimer_cntvoff() generic w.r.t. guest
timer context and spin off into a new helper method for later use.
Require callers of this new helper method to grab the kvm lock
beforehand.
No functional change intended.
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/kvm/arch_timer.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
@@ -747,22 +747,32 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)return0;}-/* Make the updates of cntvoff for all vtimer contexts atomic */-staticvoidupdate_vtimer_cntvoff(structkvm_vcpu*vcpu,u64cntvoff)+/* Make offset updates for all timer contexts atomic */+staticvoidupdate_timer_offset(structkvm_vcpu*vcpu,+enumkvm_arch_timerstimer,u64offset){inti;structkvm*kvm=vcpu->kvm;structkvm_vcpu*tmp;-mutex_lock(&kvm->lock);+lockdep_assert_held(&kvm->lock);+kvm_for_each_vcpu(i,tmp,kvm)-timer_set_offset(vcpu_vtimer(tmp),cntvoff);+timer_set_offset(vcpu_get_timer(tmp,timer),offset);/**Whencalledfromthevcpucreatepath,theCPUbeingcreatedisnot*includedintheloopabove,sowejustsetithereaswell.*/-timer_set_offset(vcpu_vtimer(vcpu),cntvoff);+timer_set_offset(vcpu_get_timer(vcpu,timer),offset);+}++staticvoidupdate_vtimer_cntvoff(structkvm_vcpu*vcpu,u64cntvoff)+{+structkvm*kvm=vcpu->kvm;++mutex_lock(&kvm->lock);+update_timer_offset(vcpu,TIMER_VTIMER,cntvoff);mutex_unlock(&kvm->lock);}
From: Andrew Jones <hidden> Date: 2021-08-04 10:20:44
On Wed, Aug 04, 2021 at 08:58:15AM +0000, Oliver Upton wrote:
quoted hunk
Presently, KVM provides no facilities for correctly migrating a guest
that depends on the physical counter-timer. Whie most guests (barring
NV, of course) should not depend on the physical counter-timer, an
operator may wish to provide a consistent view of the physical
counter-timer across migrations.
Provide userspace with a new vCPU attribute to modify the guest
counter-timer offset. Unlike KVM_REG_ARM_TIMER_OFFSET, this attribute is
hidden from the guest's architectural state. The value offsets *both*
the virtual and physical counter-timer views for the guest. Only support
this attribute on ECV systems as ECV is required for hardware offsetting
of the physical counter-timer.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/devices/vcpu.rst | 28 ++++++
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 2 +
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 122 +++++++++++++++++++++++-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 ++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 5 +
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
include/clocksource/arm_arch_timer.h | 1 +
9 files changed, 169 insertions(+), 3 deletions(-)
@@ -139,6 +139,34 @@ configured values on other VCPUs. Userspace should configure the interrupt numbers on at least one VCPU after creating all VCPUs and before running any VCPUs.+2.2. ATTRIBUTE: KVM_ARM_VCPU_TIMER_OFFSET+-----------------------------------------++:Parameters: in kvm_device_attr.addr the address for the timer offset is a+ pointer to a __u64++Returns:++ ======= ==================================+ -EFAULT Error reading/writing the provided+ parameter address+ -ENXIO Timer offsetting not implemented+ ======= ==================================++Specifies the guest's counter-timer offset from the host's virtual counter.+The guest's physical counter value is then derived by the following+equation:++ guest_cntpct = host_cntvct - KVM_ARM_VCPU_TIMER_OFFSET++The guest's virtual counter value is derived by the following equation:++ guest_cntvct = host_cntvct - KVM_REG_ARM_TIMER_OFFSET+- KVM_ARM_VCPU_TIMER_OFFSET++KVM does not allow the use of varying offset values for different vCPUs;+the last written offset value will be broadcasted to all vCPUs in a VM.+3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL ==================================
From: Andrew Jones <hidden> Date: 2021-08-04 10:21:27
On Wed, Aug 04, 2021 at 08:58:10AM +0000, Oliver Upton wrote:
quoted hunk
In some instances, a VMM may want to update the guest's counter-timer
offset in a transparent manner, meaning that changes to the hardware
value do not affect the synthetic register presented to the guest or the
VMM through said guest's architectural state. Lay the groundwork to
separate guest offset register writes from the hardware values utilized
by KVM.
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/kvm/arch_timer.c | 48 ++++++++++++++++++++++++++++++++----
include/kvm/arm_arch_timer.h | 3 +++
2 files changed, 46 insertions(+), 5 deletions(-)
@@ -749,7 +779,8 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)/* Make offset updates for all timer contexts atomic */staticvoidupdate_timer_offset(structkvm_vcpu*vcpu,-enumkvm_arch_timerstimer,u64offset)+enumkvm_arch_timerstimer,u64offset,+boolguest_visible){inti;structkvm*kvm=vcpu->kvm;
@@ -42,6 +42,9 @@ struct arch_timer_context {/* Duplicated state from arch_timer.c for convenience */u32host_timer_irq;u32host_timer_irq_flags;++/* offset relative to the host's physical counter-timer */+u64host_offset;};structtimer_map{
From: Andrew Jones <hidden> Date: 2021-08-04 10:22:40
On Wed, Aug 04, 2021 at 08:58:11AM +0000, Oliver Upton wrote:
quoted hunk
Allow userspace to access the guest's virtual counter-timer offset
through the ONE_REG interface. The value read or written is defined to
be an offset from the guest's physical counter-timer. Add some
documentation to clarify how a VMM should use this and the existing
CNTVCT_EL0.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/api.rst | 10 ++++++++++
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 11 +++++++++++
arch/arm64/kvm/guest.c | 6 +++++-
include/kvm/arm_arch_timer.h | 1 +
5 files changed, 28 insertions(+), 1 deletion(-)
@@ -2487,6 +2487,16 @@ arm64 system registers have the following id bit patterns:: derived from the register encoding for CNTV_CVAL_EL0. As this is API, it must remain this way.+..warning::++ The value of KVM_REG_ARM_TIMER_OFFSET is defined as an offset from+ the guest's view of the physical counter-timer.++ Userspace should use either KVM_REG_ARM_TIMER_OFFSET or+ KVM_REG_ARM_TIMER_CVAL to pause and resume a guest's virtual+ counter-timer. Mixed use of these registers could result in an+ unpredictable guest counter value.+ arm64 firmware pseudo-registers have the following bit pattern:: 0x6030 0000 0014 <regno:16>
From: Andrew Jones <hidden> Date: 2021-08-04 10:27:33
On Wed, Aug 04, 2021 at 08:58:16AM +0000, Oliver Upton wrote:
quoted hunk
In preparation for emulated physical counter-timer offsetting, configure
traps on every vcpu_load() for VHE systems. As before, these trap
settings do not affect host userspace, and are only active for the
guest.
Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/kvm/arch_timer.c | 10 +++++++---
arch/arm64/kvm/arm.c | 4 +---
include/kvm/arm_arch_timer.h | 2 --
3 files changed, 8 insertions(+), 8 deletions(-)
@@ -1383,12 +1387,12 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)}/*-*OnVHEsystem,weonlyneedtoconfiguretheEL2timertrapregisteronce,-*notforeveryworldswitch.+*OnVHEsystem,weonlyneedtoconfiguretheEL2timertrapregisteron+*vcpu_load(),butnoteveryworldswitchintotheguest.*ThehostkernelrunsatEL2withHCR_EL2.TGE==1,*andthismakesthosebitshavenoeffectforthehostkernelexecution.*/-voidkvm_timer_init_vhe(void)+staticvoidkvm_timer_enable_traps_vhe(void){/* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */u32cnthctl_shift=10;
From: Andrew Jones <hidden> Date: 2021-08-04 11:05:29
On Wed, Aug 04, 2021 at 08:58:18AM +0000, Oliver Upton wrote:
quoted hunk
Test that userspace adjustment of the guest physical counter-timer
results in the correct view within the guest.
Cc: Andrew Jones <redacted>
Signed-off-by: Oliver Upton <redacted>
---
.../selftests/kvm/include/aarch64/processor.h | 12 +++++++
.../kvm/system_counter_offset_test.c | 31 +++++++++++++++++--
2 files changed, 40 insertions(+), 3 deletions(-)
From: Oliver Upton <hidden> Date: 2021-08-04 11:06:37
On Wed, Aug 4, 2021 at 1:58 AM Oliver Upton [off-list ref] wrote:
KVM's current means of saving/restoring system counters is plagued with
temporal issues. At least on ARM64 and x86, we migrate the guest's
system counter by-value through the respective guest system register
values (cntvct_el0, ia32_tsc). Restoring system counters by-value is
brittle as the state is not idempotent: the host system counter is still
oscillating between the attempted save and restore. Furthermore, VMMs
may wish to transparently live migrate guest VMs, meaning that they
include the elapsed time due to live migration blackout in the guest
system counter view. The VMM thread could be preempted for any number of
reasons (scheduler, L0 hypervisor under nested) between the time that
it calculates the desired guest counter value and when KVM actually sets
this counter state.
Despite the value-based interface that we present to userspace, KVM
actually has idempotent guest controls by way of system counter offsets.
We can avoid all of the issues associated with a value-based interface
by abstracting these offset controls in new ioctls. This series
introduces new vCPU device attributes to provide userspace access to the
vCPU's system counter offset.
Patch 1 addresses a possible race in KVM_GET_CLOCK where
use_master_clock is read outside of the pvclock_gtod_sync_lock.
Patch 2 adopts Paolo's suggestion, augmenting the KVM_{GET,SET}_CLOCK
ioctls to provide userspace with a (host_tsc, realtime) instant. This is
essential for a VMM to perform precise migration of the guest's system
counters.
Patches 3-4 are some preparatory changes for exposing the TSC offset to
userspace. Patch 5 provides a vCPU attribute to provide userspace access
to the TSC offset.
Patches 6-7 implement a test for the new additions to
KVM_{GET,SET}_CLOCK.
Patch 8 fixes some assertions in the kvm device attribute helpers.
Patches 9-10 implement at test for the tsc offset attribute introduced in
patch 5.
Patches 11-12 lay the groundwork for patch 13, which exposes CNTVOFF_EL2
through the ONE_REG interface.
Patches 14-15 add test cases for userspace manipulation of the virtual
counter-timer.
Patches 16-17 add a vCPU attribute to adjust the host-guest offset of an
ARM vCPU, but only implements support for ECV hosts. Patches 18-19 add
support for non-ECV hosts by emulating physical counter offsetting.
Patch 20 adds test cases for adjusting the host-guest offset, and
finally patch 21 adds a test to measure the emulation overhead of
CNTPCT_EL2.
This series was tested on both an Ampere Mt. Jade and Haswell systems.
Unfortunately, the ECV portions of this series are untested, as there is
no ECV-capable hardware and the ARM fast models only partially implement
ECV.
Small correction: I was only using the foundation model. Apparently
the AEM FVP provides full ECV support.
Physical counter benchmark
--------------------------
The following data was collected by running 10000 iterations of the
benchmark test from Patch 21 on an Ampere Mt. Jade reference server, A 2S
machine with 2 80-core Ampere Altra SoCs. Measurements were collected
for both VHE and nVHE operation using the `kvm-arm.mode=` command-line
parameter.
nVHE
----
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 54ns | 148ns |
| Standard Deviation | 124ns | 122ns |
| 95th Percentile | 258ns | 348ns |
+--------------------+--------+---------+
VHE
---
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 53ns | 152ns |
| Standard Deviation | 92ns | 94ns |
| 95th Percentile | 204ns | 307ns |
+--------------------+--------+---------+
This series applies cleanly to kvm/queue at the following commit:
6cd974485e25 ("KVM: selftests: Add a test of an unbacked nested PI descriptor")
v1 -> v2:
- Reimplemented as vCPU device attributes instead of a distinct ioctl.
- Added the (realtime, host_tsc) instant support to KVM_{GET,SET}_CLOCK
- Changed the arm64 implementation to broadcast counter
offset values to all vCPUs in a guest. This upholds the
architectural expectations of a consistent counter-timer across CPUs.
- Fixed a bug with traps in VHE mode. We now configure traps on every
transition into a guest to handle differing VMs (trapped, emulated).
v2 -> v3:
- Added documentation for additions to KVM_{GET,SET}_CLOCK
- Added documentation for all new vCPU attributes
- Added documentation for suggested algorithm to migrate a guest's
TSC(s)
- Bug fixes throughout series
- Rename KVM_CLOCK_REAL_TIME -> KVM_CLOCK_REALTIME
v3 -> v4:
- Added patch to address incorrect device helper assertions (Drew)
- Carried Drew's r-b tags where appropriate
- x86 selftest cleanup
- Removed stale kvm_timer_init_vhe() function
- Removed unnecessary GUEST_DONE() from selftests
v4 -> v5:
- Fix typo in TSC migration algorithm
- Carry more of Drew's r-b tags
- clean up run loop logic in counter emulation benchmark (missed from
Drew's comments on v3)
v5 -> v6:
- Add fix for race in KVM_GET_CLOCK (Sean)
- Fix 32-bit build issues in series + use of uninitialized host tsc
value (Sean)
- General style cleanups
- Rework ARM virtual counter offsetting to match guest behavior. Use
the ONE_REG interface instead of a VM attribute (Marc)
- Maintain a single host-guest counter offset, which applies to both
physical and virtual counters
- Dropped some of Drew's r-b tags due to nontrivial patch changes
(sorry for the churn!)
v1: https://lore.kernel.org/kvm/20210608214742.1897483-1-oupton@google.com/
v2: https://lore.kernel.org/r/20210716212629.2232756-1-oupton@google.com
v3: https://lore.kernel.org/r/20210719184949.1385910-1-oupton@google.com
v4: https://lore.kernel.org/r/20210729001012.70394-1-oupton@google.com
v5: https://lore.kernel.org/r/20210729173300.181775-1-oupton@google.com
Oliver Upton (21):
KVM: x86: Fix potential race in KVM_GET_CLOCK
KVM: x86: Report host tsc and realtime values in KVM_GET_CLOCK
KVM: x86: Take the pvclock sync lock behind the tsc_write_lock
KVM: x86: Refactor tsc synchronization code
KVM: x86: Expose TSC offset controls to userspace
tools: arch: x86: pull in pvclock headers
selftests: KVM: Add test for KVM_{GET,SET}_CLOCK
selftests: KVM: Fix kvm device helper ioctl assertions
selftests: KVM: Add helpers for vCPU device attributes
selftests: KVM: Introduce system counter offset test
KVM: arm64: Refactor update_vtimer_cntvoff()
KVM: arm64: Separate guest/host counter offset values
KVM: arm64: Allow userspace to configure a vCPU's virtual offset
selftests: KVM: Add helper to check for register presence
selftests: KVM: Add support for aarch64 to system_counter_offset_test
arm64: cpufeature: Enumerate support for Enhanced Counter
Virtualization
KVM: arm64: Allow userspace to configure a guest's counter-timer
offset
KVM: arm64: Configure timer traps in vcpu_load() for VHE
KVM: arm64: Emulate physical counter offsetting on non-ECV systems
selftests: KVM: Test physical counter offsetting
selftests: KVM: Add counter emulation benchmark
Documentation/virt/kvm/api.rst | 52 ++-
Documentation/virt/kvm/devices/vcpu.rst | 85 ++++
Documentation/virt/kvm/locking.rst | 11 +
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 5 +
arch/arm64/include/uapi/asm/kvm.h | 2 +
arch/arm64/kernel/cpufeature.c | 10 +
arch/arm64/kvm/arch_timer.c | 224 ++++++++++-
arch/arm64/kvm/arm.c | 4 +-
arch/arm64/kvm/guest.c | 6 +-
arch/arm64/kvm/hyp/include/hyp/switch.h | 29 ++
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 +
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 16 +-
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
arch/arm64/tools/cpucaps | 1 +
arch/x86/include/asm/kvm_host.h | 4 +
arch/x86/include/uapi/asm/kvm.h | 4 +
arch/x86/kvm/x86.c | 364 +++++++++++++-----
include/clocksource/arm_arch_timer.h | 1 +
include/kvm/arm_arch_timer.h | 6 +-
include/uapi/linux/kvm.h | 7 +-
tools/arch/x86/include/asm/pvclock-abi.h | 48 +++
tools/arch/x86/include/asm/pvclock.h | 103 +++++
tools/testing/selftests/kvm/.gitignore | 3 +
tools/testing/selftests/kvm/Makefile | 4 +
.../kvm/aarch64/counter_emulation_benchmark.c | 207 ++++++++++
.../selftests/kvm/include/aarch64/processor.h | 24 ++
.../testing/selftests/kvm/include/kvm_util.h | 13 +
tools/testing/selftests/kvm/lib/kvm_util.c | 63 ++-
.../kvm/system_counter_offset_test.c | 211 ++++++++++
.../selftests/kvm/x86_64/kvm_clock_test.c | 204 ++++++++++
31 files changed, 1581 insertions(+), 143 deletions(-)
create mode 100644 tools/arch/x86/include/asm/pvclock-abi.h
create mode 100644 tools/arch/x86/include/asm/pvclock.h
create mode 100644 tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c
create mode 100644 tools/testing/selftests/kvm/system_counter_offset_test.c
create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_clock_test.c
--
2.32.0.605.g8dce9f2422-goog
From: Andrew Jones <hidden> Date: 2021-08-04 11:07:29
On Wed, Aug 04, 2021 at 08:58:17AM +0000, Oliver Upton wrote:
quoted hunk
Unfortunately, ECV hasn't yet arrived in any tangible hardware. At the
same time, controlling the guest view of the physical counter-timer is
useful. Support guest counter-timer offsetting on non-ECV systems by
trapping guest accesses to the physical counter-timer. Emulate reads of
the physical counter in the fast exit path.
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/include/asm/sysreg.h | 1 +
arch/arm64/kvm/arch_timer.c | 53 +++++++++++++++----------
arch/arm64/kvm/hyp/include/hyp/switch.h | 29 ++++++++++++++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 11 ++++-
4 files changed, 70 insertions(+), 24 deletions(-)
Whenever I see a static branch check and something else in the same
condition, I always wonder if we could trim a few instructions for
the static branch is false case by testing it first.
@@ -1392,22 +1403,29 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu) * The host kernel runs at EL2 with HCR_EL2.TGE == 1, * and this makes those bits have no effect for the host kernel execution. */-static void kvm_timer_enable_traps_vhe(void)+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu) { /* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */ u32 cnthctl_shift = 10;- u64 val;+ u64 val, mask;++ mask = CNTHCTL_EL1PCEN << cnthctl_shift;+ mask |= CNTHCTL_EL1PCTEN << cnthctl_shift;- /*- * VHE systems allow the guest direct access to the EL1 physical- * timer/counter.- */ val = read_sysreg(cnthctl_el2);- val |= (CNTHCTL_EL1PCEN << cnthctl_shift);- val |= (CNTHCTL_EL1PCTEN << cnthctl_shift); if (cpus_have_const_cap(ARM64_ECV)) val |= CNTHCTL_ECV;++ /*+ * VHE systems allow the guest direct access to the EL1 physical+ * timer/counter if offsetting isn't requested on a non-ECV system.+ */+ if (ptimer_emulation_required(vcpu))+ val &= ~mask;+ else+ val |= mask;+ write_sysreg(val, cnthctl_el2); }
@@ -1462,9 +1480,6 @@ static int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu, u64 __user *uaddr = (u64 __user *)(long)attr->addr; u64 offset;- if (!cpus_have_const_cap(ARM64_ECV))- return -ENXIO;- if (get_user(offset, uaddr)) return -EFAULT;
@@ -1539,11 +1551,8 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) switch (attr->attr) { case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:- return 0; case KVM_ARM_VCPU_TIMER_OFFSET:- if (cpus_have_const_cap(ARM64_ECV))- return 0;- break;+ return 0;
So now, if userspace wants to know when they're using an emulated
TIMER_OFFSET vs. ECV, then they'll need to check the HWCAP. I guess
that's fair. We should update the selftest to report what it's testing
when the HWCAP is available.
From: Oliver Upton <hidden> Date: 2021-08-04 22:05:15
On Wed, Aug 4, 2021 at 4:05 AM Oliver Upton [off-list ref] wrote:
On Wed, Aug 4, 2021 at 1:58 AM Oliver Upton [off-list ref] wrote:
quoted
KVM's current means of saving/restoring system counters is plagued with
temporal issues. At least on ARM64 and x86, we migrate the guest's
system counter by-value through the respective guest system register
values (cntvct_el0, ia32_tsc). Restoring system counters by-value is
brittle as the state is not idempotent: the host system counter is still
oscillating between the attempted save and restore. Furthermore, VMMs
may wish to transparently live migrate guest VMs, meaning that they
include the elapsed time due to live migration blackout in the guest
system counter view. The VMM thread could be preempted for any number of
reasons (scheduler, L0 hypervisor under nested) between the time that
it calculates the desired guest counter value and when KVM actually sets
this counter state.
Despite the value-based interface that we present to userspace, KVM
actually has idempotent guest controls by way of system counter offsets.
We can avoid all of the issues associated with a value-based interface
by abstracting these offset controls in new ioctls. This series
introduces new vCPU device attributes to provide userspace access to the
vCPU's system counter offset.
Patch 1 addresses a possible race in KVM_GET_CLOCK where
use_master_clock is read outside of the pvclock_gtod_sync_lock.
Patch 2 adopts Paolo's suggestion, augmenting the KVM_{GET,SET}_CLOCK
ioctls to provide userspace with a (host_tsc, realtime) instant. This is
essential for a VMM to perform precise migration of the guest's system
counters.
Patches 3-4 are some preparatory changes for exposing the TSC offset to
userspace. Patch 5 provides a vCPU attribute to provide userspace access
to the TSC offset.
Patches 6-7 implement a test for the new additions to
KVM_{GET,SET}_CLOCK.
Patch 8 fixes some assertions in the kvm device attribute helpers.
Patches 9-10 implement at test for the tsc offset attribute introduced in
patch 5.
Patches 11-12 lay the groundwork for patch 13, which exposes CNTVOFF_EL2
through the ONE_REG interface.
Patches 14-15 add test cases for userspace manipulation of the virtual
counter-timer.
Patches 16-17 add a vCPU attribute to adjust the host-guest offset of an
ARM vCPU, but only implements support for ECV hosts. Patches 18-19 add
support for non-ECV hosts by emulating physical counter offsetting.
Patch 20 adds test cases for adjusting the host-guest offset, and
finally patch 21 adds a test to measure the emulation overhead of
CNTPCT_EL2.
This series was tested on both an Ampere Mt. Jade and Haswell systems.
Unfortunately, the ECV portions of this series are untested, as there is
no ECV-capable hardware and the ARM fast models only partially implement
ECV.
Small correction: I was only using the foundation model. Apparently
the AEM FVP provides full ECV support.
Ok. I've now tested this series on the FVP Base RevC fast model@v8.6 +
ECV=2. Passes on VHE, fails on nVHE.
I'll respin this series with the fix for nVHE+ECV soon.
--
Thanks,
Oliver
quoted
Physical counter benchmark
--------------------------
The following data was collected by running 10000 iterations of the
benchmark test from Patch 21 on an Ampere Mt. Jade reference server, A 2S
machine with 2 80-core Ampere Altra SoCs. Measurements were collected
for both VHE and nVHE operation using the `kvm-arm.mode=` command-line
parameter.
nVHE
----
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 54ns | 148ns |
| Standard Deviation | 124ns | 122ns |
| 95th Percentile | 258ns | 348ns |
+--------------------+--------+---------+
VHE
---
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 53ns | 152ns |
| Standard Deviation | 92ns | 94ns |
| 95th Percentile | 204ns | 307ns |
+--------------------+--------+---------+
This series applies cleanly to kvm/queue at the following commit:
6cd974485e25 ("KVM: selftests: Add a test of an unbacked nested PI descriptor")
v1 -> v2:
- Reimplemented as vCPU device attributes instead of a distinct ioctl.
- Added the (realtime, host_tsc) instant support to KVM_{GET,SET}_CLOCK
- Changed the arm64 implementation to broadcast counter
offset values to all vCPUs in a guest. This upholds the
architectural expectations of a consistent counter-timer across CPUs.
- Fixed a bug with traps in VHE mode. We now configure traps on every
transition into a guest to handle differing VMs (trapped, emulated).
v2 -> v3:
- Added documentation for additions to KVM_{GET,SET}_CLOCK
- Added documentation for all new vCPU attributes
- Added documentation for suggested algorithm to migrate a guest's
TSC(s)
- Bug fixes throughout series
- Rename KVM_CLOCK_REAL_TIME -> KVM_CLOCK_REALTIME
v3 -> v4:
- Added patch to address incorrect device helper assertions (Drew)
- Carried Drew's r-b tags where appropriate
- x86 selftest cleanup
- Removed stale kvm_timer_init_vhe() function
- Removed unnecessary GUEST_DONE() from selftests
v4 -> v5:
- Fix typo in TSC migration algorithm
- Carry more of Drew's r-b tags
- clean up run loop logic in counter emulation benchmark (missed from
Drew's comments on v3)
v5 -> v6:
- Add fix for race in KVM_GET_CLOCK (Sean)
- Fix 32-bit build issues in series + use of uninitialized host tsc
value (Sean)
- General style cleanups
- Rework ARM virtual counter offsetting to match guest behavior. Use
the ONE_REG interface instead of a VM attribute (Marc)
- Maintain a single host-guest counter offset, which applies to both
physical and virtual counters
- Dropped some of Drew's r-b tags due to nontrivial patch changes
(sorry for the churn!)
v1: https://lore.kernel.org/kvm/20210608214742.1897483-1-oupton@google.com/
v2: https://lore.kernel.org/r/20210716212629.2232756-1-oupton@google.com
v3: https://lore.kernel.org/r/20210719184949.1385910-1-oupton@google.com
v4: https://lore.kernel.org/r/20210729001012.70394-1-oupton@google.com
v5: https://lore.kernel.org/r/20210729173300.181775-1-oupton@google.com
Oliver Upton (21):
KVM: x86: Fix potential race in KVM_GET_CLOCK
KVM: x86: Report host tsc and realtime values in KVM_GET_CLOCK
KVM: x86: Take the pvclock sync lock behind the tsc_write_lock
KVM: x86: Refactor tsc synchronization code
KVM: x86: Expose TSC offset controls to userspace
tools: arch: x86: pull in pvclock headers
selftests: KVM: Add test for KVM_{GET,SET}_CLOCK
selftests: KVM: Fix kvm device helper ioctl assertions
selftests: KVM: Add helpers for vCPU device attributes
selftests: KVM: Introduce system counter offset test
KVM: arm64: Refactor update_vtimer_cntvoff()
KVM: arm64: Separate guest/host counter offset values
KVM: arm64: Allow userspace to configure a vCPU's virtual offset
selftests: KVM: Add helper to check for register presence
selftests: KVM: Add support for aarch64 to system_counter_offset_test
arm64: cpufeature: Enumerate support for Enhanced Counter
Virtualization
KVM: arm64: Allow userspace to configure a guest's counter-timer
offset
KVM: arm64: Configure timer traps in vcpu_load() for VHE
KVM: arm64: Emulate physical counter offsetting on non-ECV systems
selftests: KVM: Test physical counter offsetting
selftests: KVM: Add counter emulation benchmark
Documentation/virt/kvm/api.rst | 52 ++-
Documentation/virt/kvm/devices/vcpu.rst | 85 ++++
Documentation/virt/kvm/locking.rst | 11 +
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 5 +
arch/arm64/include/uapi/asm/kvm.h | 2 +
arch/arm64/kernel/cpufeature.c | 10 +
arch/arm64/kvm/arch_timer.c | 224 ++++++++++-
arch/arm64/kvm/arm.c | 4 +-
arch/arm64/kvm/guest.c | 6 +-
arch/arm64/kvm/hyp/include/hyp/switch.h | 29 ++
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 +
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 16 +-
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
arch/arm64/tools/cpucaps | 1 +
arch/x86/include/asm/kvm_host.h | 4 +
arch/x86/include/uapi/asm/kvm.h | 4 +
arch/x86/kvm/x86.c | 364 +++++++++++++-----
include/clocksource/arm_arch_timer.h | 1 +
include/kvm/arm_arch_timer.h | 6 +-
include/uapi/linux/kvm.h | 7 +-
tools/arch/x86/include/asm/pvclock-abi.h | 48 +++
tools/arch/x86/include/asm/pvclock.h | 103 +++++
tools/testing/selftests/kvm/.gitignore | 3 +
tools/testing/selftests/kvm/Makefile | 4 +
.../kvm/aarch64/counter_emulation_benchmark.c | 207 ++++++++++
.../selftests/kvm/include/aarch64/processor.h | 24 ++
.../testing/selftests/kvm/include/kvm_util.h | 13 +
tools/testing/selftests/kvm/lib/kvm_util.c | 63 ++-
.../kvm/system_counter_offset_test.c | 211 ++++++++++
.../selftests/kvm/x86_64/kvm_clock_test.c | 204 ++++++++++
31 files changed, 1581 insertions(+), 143 deletions(-)
create mode 100644 tools/arch/x86/include/asm/pvclock-abi.h
create mode 100644 tools/arch/x86/include/asm/pvclock.h
create mode 100644 tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c
create mode 100644 tools/testing/selftests/kvm/system_counter_offset_test.c
create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_clock_test.c
--
2.32.0.605.g8dce9f2422-goog
Whenever I see a static branch check and something else in the same
condition, I always wonder if we could trim a few instructions for
the static branch is false case by testing it first.
Good point, I'll reclaim those few cycles in the next spin ;-)
quoted
@@ -1539,11 +1551,8 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) switch (attr->attr) { case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:- return 0; case KVM_ARM_VCPU_TIMER_OFFSET:- if (cpus_have_const_cap(ARM64_ECV))- return 0;- break;+ return 0;
So now, if userspace wants to know when they're using an emulated
TIMER_OFFSET vs. ECV, then they'll need to check the HWCAP. I guess
that's fair. We should update the selftest to report what it's testing
when the HWCAP is available.
Hmm...
I hadn't yet wired up the ECV cpufeature bits to an ELF HWCAP, but
this point is a bit interesting. I can see the argument being made
that we shouldn't have two ELF HWCAP bits for ECV (depending on
partial or full ECV support). ECV=0x1 is most certainly of interest to
userspace, since self-synchronized views of the counter are then
available. However, ECV=0x2 is purely of interest to EL2.
What if we only had only one ELF HWCAP bit for ECV >= 0x1? We could
let userspace read ID_AA64MMFR0_EL1.ECV if it really needs to know
about ECV = 0x2.
quoted
+ if (vcpu_ptimer(vcpu)->host_offset && !cpus_have_const_cap(ARM64_ECV))
Shouldn't we expose and reuse ptimer_emulation_required() here?
Agreed, makes it much cleaner.
quoted
+ val &= ~CNTHCTL_EL1PCTEN;
+ else
+ val |= CNTHCTL_EL1PCTEN;
write_sysreg(val, cnthctl_el2);
}
--
2.32.0.605.g8dce9f2422-goog
From: Oliver Upton <hidden> Date: 2021-08-10 00:08:47
On Wed, Aug 4, 2021 at 3:03 PM Oliver Upton [off-list ref] wrote:
On Wed, Aug 4, 2021 at 4:05 AM Oliver Upton [off-list ref] wrote:
quoted
On Wed, Aug 4, 2021 at 1:58 AM Oliver Upton [off-list ref] wrote:
quoted
KVM's current means of saving/restoring system counters is plagued with
temporal issues. At least on ARM64 and x86, we migrate the guest's
system counter by-value through the respective guest system register
values (cntvct_el0, ia32_tsc). Restoring system counters by-value is
brittle as the state is not idempotent: the host system counter is still
oscillating between the attempted save and restore. Furthermore, VMMs
may wish to transparently live migrate guest VMs, meaning that they
include the elapsed time due to live migration blackout in the guest
system counter view. The VMM thread could be preempted for any number of
reasons (scheduler, L0 hypervisor under nested) between the time that
it calculates the desired guest counter value and when KVM actually sets
this counter state.
Despite the value-based interface that we present to userspace, KVM
actually has idempotent guest controls by way of system counter offsets.
We can avoid all of the issues associated with a value-based interface
by abstracting these offset controls in new ioctls. This series
introduces new vCPU device attributes to provide userspace access to the
vCPU's system counter offset.
Patch 1 addresses a possible race in KVM_GET_CLOCK where
use_master_clock is read outside of the pvclock_gtod_sync_lock.
Patch 2 adopts Paolo's suggestion, augmenting the KVM_{GET,SET}_CLOCK
ioctls to provide userspace with a (host_tsc, realtime) instant. This is
essential for a VMM to perform precise migration of the guest's system
counters.
Patches 3-4 are some preparatory changes for exposing the TSC offset to
userspace. Patch 5 provides a vCPU attribute to provide userspace access
to the TSC offset.
Patches 6-7 implement a test for the new additions to
KVM_{GET,SET}_CLOCK.
Patch 8 fixes some assertions in the kvm device attribute helpers.
Patches 9-10 implement at test for the tsc offset attribute introduced in
patch 5.
Paolo,
Is there anything else you're waiting to see for the x86 portion of
this series after addressing Sean's comments? There's some work
remaining on the arm64 side, though I believe the two architectures
are now disjoint for this series.
--
Thanks,
Oliver
quoted
quoted
Patches 11-12 lay the groundwork for patch 13, which exposes CNTVOFF_EL2
through the ONE_REG interface.
Patches 14-15 add test cases for userspace manipulation of the virtual
counter-timer.
Patches 16-17 add a vCPU attribute to adjust the host-guest offset of an
ARM vCPU, but only implements support for ECV hosts. Patches 18-19 add
support for non-ECV hosts by emulating physical counter offsetting.
Patch 20 adds test cases for adjusting the host-guest offset, and
finally patch 21 adds a test to measure the emulation overhead of
CNTPCT_EL2.
This series was tested on both an Ampere Mt. Jade and Haswell systems.
Unfortunately, the ECV portions of this series are untested, as there is
no ECV-capable hardware and the ARM fast models only partially implement
ECV.
Small correction: I was only using the foundation model. Apparently
the AEM FVP provides full ECV support.
Ok. I've now tested this series on the FVP Base RevC fast model@v8.6 +
ECV=2. Passes on VHE, fails on nVHE.
I'll respin this series with the fix for nVHE+ECV soon.
--
Thanks,
Oliver
quoted
quoted
Physical counter benchmark
--------------------------
The following data was collected by running 10000 iterations of the
benchmark test from Patch 21 on an Ampere Mt. Jade reference server, A 2S
machine with 2 80-core Ampere Altra SoCs. Measurements were collected
for both VHE and nVHE operation using the `kvm-arm.mode=` command-line
parameter.
nVHE
----
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 54ns | 148ns |
| Standard Deviation | 124ns | 122ns |
| 95th Percentile | 258ns | 348ns |
+--------------------+--------+---------+
VHE
---
+--------------------+--------+---------+
| Metric | Native | Trapped |
+--------------------+--------+---------+
| Average | 53ns | 152ns |
| Standard Deviation | 92ns | 94ns |
| 95th Percentile | 204ns | 307ns |
+--------------------+--------+---------+
This series applies cleanly to kvm/queue at the following commit:
6cd974485e25 ("KVM: selftests: Add a test of an unbacked nested PI descriptor")
v1 -> v2:
- Reimplemented as vCPU device attributes instead of a distinct ioctl.
- Added the (realtime, host_tsc) instant support to KVM_{GET,SET}_CLOCK
- Changed the arm64 implementation to broadcast counter
offset values to all vCPUs in a guest. This upholds the
architectural expectations of a consistent counter-timer across CPUs.
- Fixed a bug with traps in VHE mode. We now configure traps on every
transition into a guest to handle differing VMs (trapped, emulated).
v2 -> v3:
- Added documentation for additions to KVM_{GET,SET}_CLOCK
- Added documentation for all new vCPU attributes
- Added documentation for suggested algorithm to migrate a guest's
TSC(s)
- Bug fixes throughout series
- Rename KVM_CLOCK_REAL_TIME -> KVM_CLOCK_REALTIME
v3 -> v4:
- Added patch to address incorrect device helper assertions (Drew)
- Carried Drew's r-b tags where appropriate
- x86 selftest cleanup
- Removed stale kvm_timer_init_vhe() function
- Removed unnecessary GUEST_DONE() from selftests
v4 -> v5:
- Fix typo in TSC migration algorithm
- Carry more of Drew's r-b tags
- clean up run loop logic in counter emulation benchmark (missed from
Drew's comments on v3)
v5 -> v6:
- Add fix for race in KVM_GET_CLOCK (Sean)
- Fix 32-bit build issues in series + use of uninitialized host tsc
value (Sean)
- General style cleanups
- Rework ARM virtual counter offsetting to match guest behavior. Use
the ONE_REG interface instead of a VM attribute (Marc)
- Maintain a single host-guest counter offset, which applies to both
physical and virtual counters
- Dropped some of Drew's r-b tags due to nontrivial patch changes
(sorry for the churn!)
v1: https://lore.kernel.org/kvm/20210608214742.1897483-1-oupton@google.com/
v2: https://lore.kernel.org/r/20210716212629.2232756-1-oupton@google.com
v3: https://lore.kernel.org/r/20210719184949.1385910-1-oupton@google.com
v4: https://lore.kernel.org/r/20210729001012.70394-1-oupton@google.com
v5: https://lore.kernel.org/r/20210729173300.181775-1-oupton@google.com
Oliver Upton (21):
KVM: x86: Fix potential race in KVM_GET_CLOCK
KVM: x86: Report host tsc and realtime values in KVM_GET_CLOCK
KVM: x86: Take the pvclock sync lock behind the tsc_write_lock
KVM: x86: Refactor tsc synchronization code
KVM: x86: Expose TSC offset controls to userspace
tools: arch: x86: pull in pvclock headers
selftests: KVM: Add test for KVM_{GET,SET}_CLOCK
selftests: KVM: Fix kvm device helper ioctl assertions
selftests: KVM: Add helpers for vCPU device attributes
selftests: KVM: Introduce system counter offset test
KVM: arm64: Refactor update_vtimer_cntvoff()
KVM: arm64: Separate guest/host counter offset values
KVM: arm64: Allow userspace to configure a vCPU's virtual offset
selftests: KVM: Add helper to check for register presence
selftests: KVM: Add support for aarch64 to system_counter_offset_test
arm64: cpufeature: Enumerate support for Enhanced Counter
Virtualization
KVM: arm64: Allow userspace to configure a guest's counter-timer
offset
KVM: arm64: Configure timer traps in vcpu_load() for VHE
KVM: arm64: Emulate physical counter offsetting on non-ECV systems
selftests: KVM: Test physical counter offsetting
selftests: KVM: Add counter emulation benchmark
Documentation/virt/kvm/api.rst | 52 ++-
Documentation/virt/kvm/devices/vcpu.rst | 85 ++++
Documentation/virt/kvm/locking.rst | 11 +
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 5 +
arch/arm64/include/uapi/asm/kvm.h | 2 +
arch/arm64/kernel/cpufeature.c | 10 +
arch/arm64/kvm/arch_timer.c | 224 ++++++++++-
arch/arm64/kvm/arm.c | 4 +-
arch/arm64/kvm/guest.c | 6 +-
arch/arm64/kvm/hyp/include/hyp/switch.h | 29 ++
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 +
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 16 +-
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
arch/arm64/tools/cpucaps | 1 +
arch/x86/include/asm/kvm_host.h | 4 +
arch/x86/include/uapi/asm/kvm.h | 4 +
arch/x86/kvm/x86.c | 364 +++++++++++++-----
include/clocksource/arm_arch_timer.h | 1 +
include/kvm/arm_arch_timer.h | 6 +-
include/uapi/linux/kvm.h | 7 +-
tools/arch/x86/include/asm/pvclock-abi.h | 48 +++
tools/arch/x86/include/asm/pvclock.h | 103 +++++
tools/testing/selftests/kvm/.gitignore | 3 +
tools/testing/selftests/kvm/Makefile | 4 +
.../kvm/aarch64/counter_emulation_benchmark.c | 207 ++++++++++
.../selftests/kvm/include/aarch64/processor.h | 24 ++
.../testing/selftests/kvm/include/kvm_util.h | 13 +
tools/testing/selftests/kvm/lib/kvm_util.c | 63 ++-
.../kvm/system_counter_offset_test.c | 211 ++++++++++
.../selftests/kvm/x86_64/kvm_clock_test.c | 204 ++++++++++
31 files changed, 1581 insertions(+), 143 deletions(-)
create mode 100644 tools/arch/x86/include/asm/pvclock-abi.h
create mode 100644 tools/arch/x86/include/asm/pvclock.h
create mode 100644 tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c
create mode 100644 tools/testing/selftests/kvm/system_counter_offset_test.c
create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_clock_test.c
--
2.32.0.605.g8dce9f2422-goog
From: Marc Zyngier <maz@kernel.org> Date: 2021-08-10 09:41:22
On Wed, 04 Aug 2021 09:58:11 +0100,
Oliver Upton [off-list ref] wrote:
quoted hunk
Allow userspace to access the guest's virtual counter-timer offset
through the ONE_REG interface. The value read or written is defined to
be an offset from the guest's physical counter-timer. Add some
documentation to clarify how a VMM should use this and the existing
CNTVCT_EL0.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/api.rst | 10 ++++++++++
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 11 +++++++++++
arch/arm64/kvm/guest.c | 6 +++++-
include/kvm/arm_arch_timer.h | 1 +
5 files changed, 28 insertions(+), 1 deletion(-)
@@ -2487,6 +2487,16 @@ arm64 system registers have the following id bit patterns:: derived from the register encoding for CNTV_CVAL_EL0. As this is API, it must remain this way.+..warning::++ The value of KVM_REG_ARM_TIMER_OFFSET is defined as an offset from+ the guest's view of the physical counter-timer.++ Userspace should use either KVM_REG_ARM_TIMER_OFFSET or+ KVM_REG_ARM_TIMER_CVAL to pause and resume a guest's virtual
You probably mean KVM_REG_ARM_TIMER_CNT here, despite the broken
encoding.
quoted hunk
+ counter-timer. Mixed use of these registers could result in an
+ unpredictable guest counter value.
+
arm64 firmware pseudo-registers have the following bit pattern::
0x6030 0000 0014 <regno:16>
I don't think we can use the encoding for CNTPOFF_EL2 here, as it will
eventually clash with a NV guest using the same feature for its own
purpose. We don't want this offset to overlap with any of the existing
features.
I actually liked your previous proposal of controlling the physical
offset via a device property, as it clearly indicated that you were
dealing with non-architectural state.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marc Zyngier <maz@kernel.org> Date: 2021-08-10 09:44:36
On Wed, 04 Aug 2021 09:58:14 +0100,
Oliver Upton [off-list ref] wrote:
quoted hunk
Introduce a new cpucap to indicate if the system supports full enhanced
counter virtualization (i.e. ID_AA64MMFR0_EL1.ECV==0x2).
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/include/asm/sysreg.h | 2 ++
arch/arm64/kernel/cpufeature.c | 10 ++++++++++
arch/arm64/tools/cpucaps | 1 +
3 files changed, 13 insertions(+)
@@ -3,6 +3,7 @@ # Internal CPU capabilities constants, keep this list sorted BTI+ECV # Unreliable: use system_supports_32bit_el0() instead. HAS_32BIT_EL0_DO_NOT_USE HAS_32BIT_EL1
As discussed in another context, we probably want both ECV and ECV2 to
distinguish the two feature sets that ECV has so far.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-10 09:54:07
On Tue, Aug 10, 2021 at 2:35 AM Marc Zyngier [off-list ref] wrote:
On Wed, 04 Aug 2021 09:58:11 +0100,
Oliver Upton [off-list ref] wrote:
quoted
Allow userspace to access the guest's virtual counter-timer offset
through the ONE_REG interface. The value read or written is defined to
be an offset from the guest's physical counter-timer. Add some
documentation to clarify how a VMM should use this and the existing
CNTVCT_EL0.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/api.rst | 10 ++++++++++
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 11 +++++++++++
arch/arm64/kvm/guest.c | 6 +++++-
include/kvm/arm_arch_timer.h | 1 +
5 files changed, 28 insertions(+), 1 deletion(-)
@@ -2487,6 +2487,16 @@ arm64 system registers have the following id bit patterns:: derived from the register encoding for CNTV_CVAL_EL0. As this is API, it must remain this way.+..warning::++ The value of KVM_REG_ARM_TIMER_OFFSET is defined as an offset from+ the guest's view of the physical counter-timer.++ Userspace should use either KVM_REG_ARM_TIMER_OFFSET or+ KVM_REG_ARM_TIMER_CVAL to pause and resume a guest's virtual
You probably mean KVM_REG_ARM_TIMER_CNT here, despite the broken
encoding.
Indeed I do!
quoted
+ counter-timer. Mixed use of these registers could result in an
+ unpredictable guest counter value.
+
arm64 firmware pseudo-registers have the following bit pattern::
0x6030 0000 0014 <regno:16>
I don't think we can use the encoding for CNTPOFF_EL2 here, as it will
eventually clash with a NV guest using the same feature for its own
purpose. We don't want this offset to overlap with any of the existing
features.
I actually liked your previous proposal of controlling the physical
offset via a device property, as it clearly indicated that you were
dealing with non-architectural state.
That's actually exactly what I did here :) That said, the macro name
is horribly obfuscated from CNTVOFF_EL2. I did this for the sake of
symmetry with other virtual counter-timer registers above, though this
may warrant special casing given the fact that we have a similarly
named device attribute to handle the physical offset.
--
Thanks,
Oliver
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marc Zyngier <maz@kernel.org> Date: 2021-08-10 10:59:37
On Wed, 04 Aug 2021 09:58:15 +0100,
Oliver Upton [off-list ref] wrote:
Presently, KVM provides no facilities for correctly migrating a guest
that depends on the physical counter-timer. Whie most guests (barring
nit: While
quoted hunk
NV, of course) should not depend on the physical counter-timer, an
operator may wish to provide a consistent view of the physical
counter-timer across migrations.
Provide userspace with a new vCPU attribute to modify the guest
counter-timer offset. Unlike KVM_REG_ARM_TIMER_OFFSET, this attribute is
hidden from the guest's architectural state. The value offsets *both*
the virtual and physical counter-timer views for the guest. Only support
this attribute on ECV systems as ECV is required for hardware offsetting
of the physical counter-timer.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/devices/vcpu.rst | 28 ++++++
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 2 +
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 122 +++++++++++++++++++++++-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 ++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 5 +
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
include/clocksource/arm_arch_timer.h | 1 +
9 files changed, 169 insertions(+), 3 deletions(-)
@@ -139,6 +139,34 @@ configured values on other VCPUs. Userspace should configure the interrupt numbers on at least one VCPU after creating all VCPUs and before running any VCPUs.+2.2. ATTRIBUTE: KVM_ARM_VCPU_TIMER_OFFSET+-----------------------------------------++:Parameters: in kvm_device_attr.addr the address for the timer offset is a+ pointer to a __u64++Returns:++ ======= ==================================+ -EFAULT Error reading/writing the provided+ parameter address+ -ENXIO Timer offsetting not implemented+ ======= ==================================++Specifies the guest's counter-timer offset from the host's virtual counter.+The guest's physical counter value is then derived by the following+equation:++ guest_cntpct = host_cntvct - KVM_ARM_VCPU_TIMER_OFFSET++The guest's virtual counter value is derived by the following equation:++ guest_cntvct = host_cntvct - KVM_REG_ARM_TIMER_OFFSET+- KVM_ARM_VCPU_TIMER_OFFSET++KVM does not allow the use of varying offset values for different vCPUs;+the last written offset value will be broadcasted to all vCPUs in a VM.+3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL ==================================
@@ -932,6 +960,29 @@ u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) return (u64)-1; }+/**+ * kvm_arm_timer_read_offset - returns the guest value of CNTVOFF_EL2.+ * @vcpu: the vcpu pointer+ *+ * Computes the guest value of CNTVOFF_EL2 by subtracting the physical+ * counter offset. Note that KVM defines CNTVOFF_EL2 as the offset from the+ * guest's physical counter-timer, not the host's.+ *+ * Returns: the guest value for CNTVOFF_EL2+ */+static u64 kvm_arm_timer_read_offset(struct kvm_vcpu *vcpu)+{+ struct kvm *kvm = vcpu->kvm;+ u64 offset;++ mutex_lock(&kvm->lock);+ offset = timer_get_offset(vcpu_vtimer(vcpu)) -+ timer_get_offset(vcpu_ptimer(vcpu));
@@ -957,7 +1008,7 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu, break; case TIMER_REG_OFFSET:- val = timer_get_offset(timer);+ val = kvm_arm_timer_read_offset(vcpu); break; default:
@@ -1350,6 +1401,9 @@ void kvm_timer_init_vhe(void) val = read_sysreg(cnthctl_el2); val |= (CNTHCTL_EL1PCEN << cnthctl_shift); val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);++ if (cpus_have_const_cap(ARM64_ECV))+ val |= CNTHCTL_ECV;
I cannot immediately see where you are doing the equivalent enablement
of ECV on the nVHE path. Obviously, it has to be done eagerly from
EL2, together with the rest of the EL1 timer setup. Something like:
You also want to document that SCR_EL3.ECVEn has to be set to 1 for
this to work (see Documentation/arm64/booting.txt). And if it isn't,
the firmware better handle the CNTPOFF_EL2 traps correctly...
What firmware did you use for this? I think we need to update the boot
wrapper, but that's something that can be done in parallel.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marc Zyngier <maz@kernel.org> Date: 2021-08-10 11:30:58
On Wed, 04 Aug 2021 09:58:17 +0100,
Oliver Upton [off-list ref] wrote:
quoted hunk
Unfortunately, ECV hasn't yet arrived in any tangible hardware. At the
same time, controlling the guest view of the physical counter-timer is
useful. Support guest counter-timer offsetting on non-ECV systems by
trapping guest accesses to the physical counter-timer. Emulate reads of
the physical counter in the fast exit path.
Signed-off-by: Oliver Upton <redacted>
---
arch/arm64/include/asm/sysreg.h | 1 +
arch/arm64/kvm/arch_timer.c | 53 +++++++++++++++----------
arch/arm64/kvm/hyp/include/hyp/switch.h | 29 ++++++++++++++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 11 ++++-
4 files changed, 70 insertions(+), 24 deletions(-)
@@ -1392,22 +1403,29 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu) * The host kernel runs at EL2 with HCR_EL2.TGE == 1, * and this makes those bits have no effect for the host kernel execution. */-static void kvm_timer_enable_traps_vhe(void)+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu) { /* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */ u32 cnthctl_shift = 10;- u64 val;+ u64 val, mask;++ mask = CNTHCTL_EL1PCEN << cnthctl_shift;+ mask |= CNTHCTL_EL1PCTEN << cnthctl_shift;- /*- * VHE systems allow the guest direct access to the EL1 physical- * timer/counter.- */ val = read_sysreg(cnthctl_el2);- val |= (CNTHCTL_EL1PCEN << cnthctl_shift);- val |= (CNTHCTL_EL1PCTEN << cnthctl_shift); if (cpus_have_const_cap(ARM64_ECV)) val |= CNTHCTL_ECV;++ /*+ * VHE systems allow the guest direct access to the EL1 physical+ * timer/counter if offsetting isn't requested on a non-ECV system.+ */+ if (ptimer_emulation_required(vcpu))+ val &= ~mask;+ else+ val |= mask;+ write_sysreg(val, cnthctl_el2); }
@@ -1462,9 +1480,6 @@ static int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu, u64 __user *uaddr = (u64 __user *)(long)attr->addr; u64 offset;- if (!cpus_have_const_cap(ARM64_ECV))- return -ENXIO;- if (get_user(offset, uaddr)) return -EFAULT;
You also want to check for CNTPCTSS_EL0 which will also be caught by
this trap.
quoted hunk
+
+ rt = kvm_vcpu_sys_get_rt(vcpu);
+ rv = __timer_read_cntpct(vcpu);
+ vcpu_set_reg(vcpu, rt, rv);
+ __kvm_skip_instr(vcpu);
+ return true;
+}
+
/*
* Return true when we were able to fixup the guest exit and should return to
* the guest, false when we should restore the host state and return to the
@@ -439,6 +465,9 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code) if (*exit_code != ARM_EXCEPTION_TRAP) goto exit;+ if (__hyp_handle_counter(vcpu))+ goto guest;+ if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) && kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 && handle_tx2_tvm(vcpu))
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marc Zyngier <maz@kernel.org> Date: 2021-08-10 12:34:01
On Tue, 10 Aug 2021 01:04:38 +0100,
Oliver Upton [off-list ref] wrote:
On Wed, Aug 4, 2021 at 3:03 PM Oliver Upton [off-list ref] wrote:
quoted
On Wed, Aug 4, 2021 at 4:05 AM Oliver Upton [off-list ref] wrote:
quoted
On Wed, Aug 4, 2021 at 1:58 AM Oliver Upton [off-list ref] wrote:
quoted
KVM's current means of saving/restoring system counters is plagued with
temporal issues. At least on ARM64 and x86, we migrate the guest's
system counter by-value through the respective guest system register
values (cntvct_el0, ia32_tsc). Restoring system counters by-value is
brittle as the state is not idempotent: the host system counter is still
oscillating between the attempted save and restore. Furthermore, VMMs
may wish to transparently live migrate guest VMs, meaning that they
include the elapsed time due to live migration blackout in the guest
system counter view. The VMM thread could be preempted for any number of
reasons (scheduler, L0 hypervisor under nested) between the time that
it calculates the desired guest counter value and when KVM actually sets
this counter state.
Despite the value-based interface that we present to userspace, KVM
actually has idempotent guest controls by way of system counter offsets.
We can avoid all of the issues associated with a value-based interface
by abstracting these offset controls in new ioctls. This series
introduces new vCPU device attributes to provide userspace access to the
vCPU's system counter offset.
Patch 1 addresses a possible race in KVM_GET_CLOCK where
use_master_clock is read outside of the pvclock_gtod_sync_lock.
Patch 2 adopts Paolo's suggestion, augmenting the KVM_{GET,SET}_CLOCK
ioctls to provide userspace with a (host_tsc, realtime) instant. This is
essential for a VMM to perform precise migration of the guest's system
counters.
Patches 3-4 are some preparatory changes for exposing the TSC offset to
userspace. Patch 5 provides a vCPU attribute to provide userspace access
to the TSC offset.
Patches 6-7 implement a test for the new additions to
KVM_{GET,SET}_CLOCK.
Patch 8 fixes some assertions in the kvm device attribute helpers.
Patches 9-10 implement at test for the tsc offset attribute introduced in
patch 5.
Paolo,
Is there anything else you're waiting to see for the x86 portion of
this series after addressing Sean's comments? There's some work
remaining on the arm64 side, though I believe the two architectures
are now disjoint for this series.
I think at this stage it would make sense to split the series in two
and drive them independently.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-10 17:57:06
On Tue, Aug 10, 2021 at 3:56 AM Marc Zyngier [off-list ref] wrote:
On Wed, 04 Aug 2021 09:58:15 +0100,
Oliver Upton [off-list ref] wrote:
quoted
Presently, KVM provides no facilities for correctly migrating a guest
that depends on the physical counter-timer. Whie most guests (barring
nit: While
Ack.
quoted
NV, of course) should not depend on the physical counter-timer, an
operator may wish to provide a consistent view of the physical
counter-timer across migrations.
Provide userspace with a new vCPU attribute to modify the guest
counter-timer offset. Unlike KVM_REG_ARM_TIMER_OFFSET, this attribute is
hidden from the guest's architectural state. The value offsets *both*
the virtual and physical counter-timer views for the guest. Only support
this attribute on ECV systems as ECV is required for hardware offsetting
of the physical counter-timer.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/devices/vcpu.rst | 28 ++++++
arch/arm64/include/asm/kvm_asm.h | 2 +
arch/arm64/include/asm/sysreg.h | 2 +
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 122 +++++++++++++++++++++++-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 6 ++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 5 +
arch/arm64/kvm/hyp/vhe/timer-sr.c | 5 +
include/clocksource/arm_arch_timer.h | 1 +
9 files changed, 169 insertions(+), 3 deletions(-)
@@ -139,6 +139,34 @@ configured values on other VCPUs. Userspace should configure the interrupt numbers on at least one VCPU after creating all VCPUs and before running any VCPUs.+2.2. ATTRIBUTE: KVM_ARM_VCPU_TIMER_OFFSET+-----------------------------------------++:Parameters: in kvm_device_attr.addr the address for the timer offset is a+ pointer to a __u64++Returns:++ ======= ==================================+ -EFAULT Error reading/writing the provided+ parameter address+ -ENXIO Timer offsetting not implemented+ ======= ==================================++Specifies the guest's counter-timer offset from the host's virtual counter.+The guest's physical counter value is then derived by the following+equation:++ guest_cntpct = host_cntvct - KVM_ARM_VCPU_TIMER_OFFSET++The guest's virtual counter value is derived by the following equation:++ guest_cntvct = host_cntvct - KVM_REG_ARM_TIMER_OFFSET+- KVM_ARM_VCPU_TIMER_OFFSET++KVM does not allow the use of varying offset values for different vCPUs;+the last written offset value will be broadcasted to all vCPUs in a VM.+3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL ==================================
@@ -932,6 +960,29 @@ u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) return (u64)-1; }+/**+ * kvm_arm_timer_read_offset - returns the guest value of CNTVOFF_EL2.+ * @vcpu: the vcpu pointer+ *+ * Computes the guest value of CNTVOFF_EL2 by subtracting the physical+ * counter offset. Note that KVM defines CNTVOFF_EL2 as the offset from the+ * guest's physical counter-timer, not the host's.+ *+ * Returns: the guest value for CNTVOFF_EL2+ */+static u64 kvm_arm_timer_read_offset(struct kvm_vcpu *vcpu)+{+ struct kvm *kvm = vcpu->kvm;+ u64 offset;++ mutex_lock(&kvm->lock);+ offset = timer_get_offset(vcpu_vtimer(vcpu)) -+ timer_get_offset(vcpu_ptimer(vcpu));
@@ -957,7 +1008,7 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu, break; case TIMER_REG_OFFSET:- val = timer_get_offset(timer);+ val = kvm_arm_timer_read_offset(vcpu); break; default:
@@ -1350,6 +1401,9 @@ void kvm_timer_init_vhe(void) val = read_sysreg(cnthctl_el2); val |= (CNTHCTL_EL1PCEN << cnthctl_shift); val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);++ if (cpus_have_const_cap(ARM64_ECV))+ val |= CNTHCTL_ECV;
I cannot immediately see where you are doing the equivalent enablement
of ECV on the nVHE path. Obviously, it has to be done eagerly from
EL2, together with the rest of the EL1 timer setup. Something like:
Yep, I had caught this when I was actually able to run the Base FVP. I
have a fix (same as yours, basically) but held back until you reviewed
to avoid storming your inbox :)
You also want to document that SCR_EL3.ECVEn has to be set to 1 for
this to work (see Documentation/arm64/booting.txt). And if it isn't,
the firmware better handle the CNTPOFF_EL2 traps correctly...
I'll grab the popcorn now ;-) Adding docs for this, good idea.
What firmware did you use for this? I think we need to update the boot
wrapper, but that's something that can be done in parallel.
I had actually just done a direct boot from ARM-TF -> Linux, nothing
else in between.
--
Thanks,
Oliver
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
You also want to document that SCR_EL3.ECVEn has to be set to 1 for
this to work (see Documentation/arm64/booting.txt). And if it isn't,
the firmware better handle the CNTPOFF_EL2 traps correctly...
I'll grab the popcorn now ;-) Adding docs for this, good idea.
quoted
What firmware did you use for this? I think we need to update the boot
wrapper, but that's something that can be done in parallel.
I had actually just done a direct boot from ARM-TF -> Linux, nothing
else in between.
Ah, right. I tend to use the boot-wrapper[1] to build a single binary
that contains the 'boot loader', DT and kernel. Using ATF is probably
more representative of the final thing, but the boot-wrapper is dead
easy to hack on...
Thanks,
M.
[1] git://git.kernel.org/pub/scm/linux/kernel/git/mark/boot-wrapper-aarch64.git
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2021-08-11 12:41:09
On 04/08/21 10:57, Oliver Upton wrote:
Sean noticed that KVM_GET_CLOCK was checking kvm_arch.use_master_clock
outside of the pvclock sync lock. This is problematic, as the clock
value written to the user may or may not actually correspond to a stable
TSC.
Fix the race by populating the entire kvm_clock_data structure behind
the pvclock_gtod_sync_lock.
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Oliver Upton <redacted>
---
arch/x86/kvm/x86.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
I had a completely independent patch that fixed the same race. It unifies
the read sides of tsc_write_lock and pvclock_gtod_sync_lock into a seqcount
(and replaces pvclock_gtod_sync_lock with kvm->lock on the write side).
I attach it now (based on https://lore.kernel.org/kvm/20210811102356.3406687-1-pbonzini@redhat.com/T/#t),
but the testing was extremely light so I'm not sure I will be able to include
it in 5.15.
Paolo
-------------- 8< -------------
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Thu, 8 Apr 2021 05:03:44 -0400
Subject: [PATCH] kvm: x86: protect masterclock with a seqcount
Protect the reference point for kvmclock with a seqcount, so that
kvmclock updates for all vCPUs can proceed in parallel. Xen runstate
updates will also run in parallel and not bounce the kvmclock cacheline.
This also makes it possible to use KVM_REQ_CLOCK_UPDATE (which will
block on the seqcount) to prevent entering in the guests until
pvclock_update_vm_gtod_copy is complete, and thus to get rid of
KVM_REQ_MCLOCK_INPROGRESS.
nr_vcpus_matched_tsc is updated outside pvclock_update_vm_gtod_copy
though, so a spinlock must be kept for that one.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
@@ -29,6 +29,8 @@ The acquisition orders for mutexes are as follows: On x86:+- the seqcount kvm->arch.pvclock_sc is written under kvm->lock.+- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock- kvm->arch.mmu_lock is an rwlock. kvm->arch.tdp_mmu_pages_lock is
@@ -2758,25 +2759,26 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)staticvoidkvm_start_pvclock_update(structkvm*kvm){structkvm_arch*ka=&kvm->arch;-kvm_make_all_cpus_request(kvm,KVM_REQ_MCLOCK_INPROGRESS);-/* no guest entries from this point */-spin_lock_irq(&ka->pvclock_gtod_sync_lock);+mutex_lock(&kvm->lock);+/*+*write_seqcount_begindisablespreemption.Thisisneedednotjust+*toavoidlivelock,butalsobecausethepreemptnotifierisareader+*forka->pvclock_sc.+*/+write_seqcount_begin(&ka->pvclock_sc);+kvm_make_all_cpus_request(kvm,+KVM_REQ_CLOCK_UPDATE|KVM_REQUEST_WAIT|KVM_REQUEST_NO_WAKEUP);++/* no guest entries from this point until write_seqcount_end */}staticvoidkvm_end_pvclock_update(structkvm*kvm){structkvm_arch*ka=&kvm->arch;-structkvm_vcpu*vcpu;-inti;-spin_unlock_irq(&ka->pvclock_gtod_sync_lock);-kvm_for_each_vcpu(i,vcpu,kvm)-kvm_make_request(KVM_REQ_CLOCK_UPDATE,vcpu);--/* guest entries allowed */-kvm_for_each_vcpu(i,vcpu,kvm)-kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS,vcpu);+write_seqcount_end(&ka->pvclock_sc);+mutex_unlock(&kvm->lock);}staticvoidkvm_update_masterclock(structkvm*kvm)
@@ -2787,27 +2789,21 @@ static void kvm_update_masterclock(struct kvm *kvm)kvm_end_pvclock_update(kvm);}-u64get_kvmclock_ns(structkvm*kvm)+staticu64__get_kvmclock_ns(structkvm*kvm){structkvm_arch*ka=&kvm->arch;structpvclock_vcpu_time_infohv_clock;-unsignedlongflags;u64ret;-spin_lock_irqsave(&ka->pvclock_gtod_sync_lock,flags);-if(!ka->use_master_clock){-spin_unlock_irqrestore(&ka->pvclock_gtod_sync_lock,flags);+if(!ka->use_master_clock)returnget_kvmclock_base_ns()+ka->kvmclock_offset;-}--hv_clock.tsc_timestamp=ka->master_cycle_now;-hv_clock.system_time=ka->master_kernel_ns+ka->kvmclock_offset;-spin_unlock_irqrestore(&ka->pvclock_gtod_sync_lock,flags);/* both __this_cpu_read() and rdtsc() should be on the same cpu */get_cpu();if(__this_cpu_read(cpu_tsc_khz)){+hv_clock.tsc_timestamp=ka->master_cycle_now;+hv_clock.system_time=ka->master_kernel_ns+ka->kvmclock_offset;kvm_get_time_scale(NSEC_PER_SEC,__this_cpu_read(cpu_tsc_khz)*1000LL,&hv_clock.tsc_shift,&hv_clock.tsc_to_system_mul);
@@ -2896,13 +2906,14 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)*IfthehostusesTSCclock,thenpassthroughTSCasstable*totheguest.*/-spin_lock_irqsave(&ka->pvclock_gtod_sync_lock,flags);-use_master_clock=ka->use_master_clock;-if(use_master_clock){-host_tsc=ka->master_cycle_now;-kernel_ns=ka->master_kernel_ns;-}-spin_unlock_irqrestore(&ka->pvclock_gtod_sync_lock,flags);+seq=read_seqcount_begin(&ka->pvclock_sc);+do{+use_master_clock=ka->use_master_clock;+if(use_master_clock){+host_tsc=ka->master_cycle_now;+kernel_ns=ka->master_kernel_ns;+}+}while(read_seqcount_retry(&ka->pvclock_sc,seq));/* Keep irq disabled to prevent changes to the clock */local_irq_save(flags);
@@ -6098,11 +6109,13 @@ long kvm_arch_vm_ioctl(struct file *filp,}caseKVM_GET_CLOCK:{structkvm_clock_datauser_ns;-u64now_ns;+unsignedseq;-now_ns=get_kvmclock_ns(kvm);-user_ns.clock=now_ns;-user_ns.flags=kvm->arch.use_master_clock?KVM_CLOCK_TSC_STABLE:0;+do{+seq=read_seqcount_begin(&kvm->arch.pvclock_sc);+user_ns.clock=__get_kvmclock_ns(kvm);+user_ns.flags=kvm->arch.use_master_clock?KVM_CLOCK_TSC_STABLE:0;+}while(read_seqcount_retry(&kvm->arch.pvclock_sc,seq));memset(&user_ns.pad,0,sizeof(user_ns.pad));r=-EFAULT;
@@ -11144,8 +11157,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)raw_spin_lock_init(&kvm->arch.tsc_write_lock);mutex_init(&kvm->arch.apic_map_lock);-spin_lock_init(&kvm->arch.pvclock_gtod_sync_lock);-+seqcount_mutex_init(&kvm->arch.pvclock_sc,&kvm->lock);kvm->arch.kvmclock_offset=-get_kvmclock_base_ns();pvclock_update_vm_gtod_copy(kvm);
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2021-08-11 13:07:58
On 04/08/21 10:57, Oliver Upton wrote:
KVM's current means of saving/restoring system counters is plagued with
temporal issues. At least on ARM64 and x86, we migrate the guest's
system counter by-value through the respective guest system register
values (cntvct_el0, ia32_tsc). Restoring system counters by-value is
brittle as the state is not idempotent: the host system counter is still
oscillating between the attempted save and restore. Furthermore, VMMs
may wish to transparently live migrate guest VMs, meaning that they
include the elapsed time due to live migration blackout in the guest
system counter view. The VMM thread could be preempted for any number of
reasons (scheduler, L0 hypervisor under nested) between the time that
it calculates the desired guest counter value and when KVM actually sets
this counter state.
Despite the value-based interface that we present to userspace, KVM
actually has idempotent guest controls by way of system counter offsets.
We can avoid all of the issues associated with a value-based interface
by abstracting these offset controls in new ioctls. This series
introduces new vCPU device attributes to provide userspace access to the
vCPU's system counter offset.
Patch 1 addresses a possible race in KVM_GET_CLOCK where
use_master_clock is read outside of the pvclock_gtod_sync_lock.
Patch 2 adopts Paolo's suggestion, augmenting the KVM_{GET,SET}_CLOCK
ioctls to provide userspace with a (host_tsc, realtime) instant. This is
essential for a VMM to perform precise migration of the guest's system
counters.
Patches 3-4 are some preparatory changes for exposing the TSC offset to
userspace. Patch 5 provides a vCPU attribute to provide userspace access
to the TSC offset.
Patches 6-7 implement a test for the new additions to
KVM_{GET,SET}_CLOCK.
Patch 8 fixes some assertions in the kvm device attribute helpers.
Patches 9-10 implement at test for the tsc offset attribute introduced in
patch 5.
The x86 parts look good, except that patch 3 is a bit redundant with my
idea of altogether getting rid of the pvclock_gtod_sync_lock. That said
I agree that patches 1 and 2 (and extracting kvm_vm_ioctl_get_clock and
kvm_vm_ioctl_set_clock) should be done before whatever locking changes
have to be done.
Time is ticking for 5.15 due to my vacation, I'll see if I have some
time to look at it further next week.
I agree that arm64 can be done separately from x86.
Paolo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marc Zyngier <maz@kernel.org> Date: 2021-08-11 15:24:56
On Tue, 10 Aug 2021 10:44:01 +0100,
Oliver Upton [off-list ref] wrote:
On Tue, Aug 10, 2021 at 2:35 AM Marc Zyngier [off-list ref] wrote:
quoted
On Wed, 04 Aug 2021 09:58:11 +0100,
Oliver Upton [off-list ref] wrote:
quoted
Allow userspace to access the guest's virtual counter-timer offset
through the ONE_REG interface. The value read or written is defined to
be an offset from the guest's physical counter-timer. Add some
documentation to clarify how a VMM should use this and the existing
CNTVCT_EL0.
Signed-off-by: Oliver Upton <redacted>
---
Documentation/virt/kvm/api.rst | 10 ++++++++++
arch/arm64/include/uapi/asm/kvm.h | 1 +
arch/arm64/kvm/arch_timer.c | 11 +++++++++++
arch/arm64/kvm/guest.c | 6 +++++-
include/kvm/arm_arch_timer.h | 1 +
5 files changed, 28 insertions(+), 1 deletion(-)
@@ -2487,6 +2487,16 @@ arm64 system registers have the following id bit patterns:: derived from the register encoding for CNTV_CVAL_EL0. As this is API, it must remain this way.+..warning::++ The value of KVM_REG_ARM_TIMER_OFFSET is defined as an offset from+ the guest's view of the physical counter-timer.++ Userspace should use either KVM_REG_ARM_TIMER_OFFSET or+ KVM_REG_ARM_TIMER_CVAL to pause and resume a guest's virtual
You probably mean KVM_REG_ARM_TIMER_CNT here, despite the broken
encoding.
Indeed I do!
quoted
quoted
+ counter-timer. Mixed use of these registers could result in an
+ unpredictable guest counter value.
+
arm64 firmware pseudo-registers have the following bit pattern::
0x6030 0000 0014 <regno:16>
I don't think we can use the encoding for CNTPOFF_EL2 here, as it will
eventually clash with a NV guest using the same feature for its own
purpose. We don't want this offset to overlap with any of the existing
features.
I actually liked your previous proposal of controlling the physical
offset via a device property, as it clearly indicated that you were
dealing with non-architectural state.
That's actually exactly what I did here :) That said, the macro name
is horribly obfuscated from CNTVOFF_EL2. I did this for the sake of
symmetry with other virtual counter-timer registers above, though this
may warrant special casing given the fact that we have a similarly
named device attribute to handle the physical offset.
Gah, you are of course right. Ignore my rambling. The name is fine (or
at least in keeping with existing quality level of the making).
For the physical offset, something along the lines of
KVM_ARM_VCPU_TIMER_PHYS_OFFSET is probably right (but feel free to be
creative, I'm terrible at this stuff [1]).
Thanks,
M.
[1] https://twitter.com/codinghorror/status/506010907021828096?lang=en
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-11 18:58:54
On Wed, Aug 11, 2021 at 6:05 AM Paolo Bonzini [off-list ref] wrote:
On 04/08/21 10:57, Oliver Upton wrote:
quoted
KVM's current means of saving/restoring system counters is plagued with
temporal issues. At least on ARM64 and x86, we migrate the guest's
system counter by-value through the respective guest system register
values (cntvct_el0, ia32_tsc). Restoring system counters by-value is
brittle as the state is not idempotent: the host system counter is still
oscillating between the attempted save and restore. Furthermore, VMMs
may wish to transparently live migrate guest VMs, meaning that they
include the elapsed time due to live migration blackout in the guest
system counter view. The VMM thread could be preempted for any number of
reasons (scheduler, L0 hypervisor under nested) between the time that
it calculates the desired guest counter value and when KVM actually sets
this counter state.
Despite the value-based interface that we present to userspace, KVM
actually has idempotent guest controls by way of system counter offsets.
We can avoid all of the issues associated with a value-based interface
by abstracting these offset controls in new ioctls. This series
introduces new vCPU device attributes to provide userspace access to the
vCPU's system counter offset.
Patch 1 addresses a possible race in KVM_GET_CLOCK where
use_master_clock is read outside of the pvclock_gtod_sync_lock.
Patch 2 adopts Paolo's suggestion, augmenting the KVM_{GET,SET}_CLOCK
ioctls to provide userspace with a (host_tsc, realtime) instant. This is
essential for a VMM to perform precise migration of the guest's system
counters.
Patches 3-4 are some preparatory changes for exposing the TSC offset to
userspace. Patch 5 provides a vCPU attribute to provide userspace access
to the TSC offset.
Patches 6-7 implement a test for the new additions to
KVM_{GET,SET}_CLOCK.
Patch 8 fixes some assertions in the kvm device attribute helpers.
Patches 9-10 implement at test for the tsc offset attribute introduced in
patch 5.
The x86 parts look good, except that patch 3 is a bit redundant with my
idea of altogether getting rid of the pvclock_gtod_sync_lock. That said
I agree that patches 1 and 2 (and extracting kvm_vm_ioctl_get_clock and
kvm_vm_ioctl_set_clock) should be done before whatever locking changes
have to be done.
Following up on patch 3.
Time is ticking for 5.15 due to my vacation, I'll see if I have some
time to look at it further next week.
I agree that arm64 can be done separately from x86.
Marc, just a disclaimer:
I'm going to separate these two series, although there will still
exist dependencies in the selftests changes. Otherwise, kernel changes
are disjoint.
--
Thanks,
Oliver
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marc Zyngier <maz@kernel.org> Date: 2021-08-11 19:03:53
On Wed, 11 Aug 2021 19:56:22 +0100,
Oliver Upton [off-list ref] wrote:
[...]
quoted
Time is ticking for 5.15 due to my vacation, I'll see if I have some
time to look at it further next week.
I agree that arm64 can be done separately from x86.
Marc, just a disclaimer:
I'm going to separate these two series, although there will still
exist dependencies in the selftests changes. Otherwise, kernel changes
are disjoint.
No problem. The selftests can even sit in a third series if that makes
it easier.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-13 10:42:19
Hi Paolo,
On Wed, Aug 11, 2021 at 5:23 AM Paolo Bonzini [off-list ref] wrote:
On 04/08/21 10:57, Oliver Upton wrote:
quoted
Sean noticed that KVM_GET_CLOCK was checking kvm_arch.use_master_clock
outside of the pvclock sync lock. This is problematic, as the clock
value written to the user may or may not actually correspond to a stable
TSC.
Fix the race by populating the entire kvm_clock_data structure behind
the pvclock_gtod_sync_lock.
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Oliver Upton <redacted>
---
arch/x86/kvm/x86.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
I had a completely independent patch that fixed the same race. It unifies
the read sides of tsc_write_lock and pvclock_gtod_sync_lock into a seqcount
(and replaces pvclock_gtod_sync_lock with kvm->lock on the write side).
Might it make sense to fix this issue under the existing locking
scheme, then shift to what you're proposing? I say that, but the
locking change in 03/21 would most certainly have a short lifetime
until this patch supersedes it.
quoted hunk
I attach it now (based on https://lore.kernel.org/kvm/20210811102356.3406687-1-pbonzini@redhat.com/T/#t),
but the testing was extremely light so I'm not sure I will be able to include
it in 5.15.
Paolo
-------------- 8< -------------
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Thu, 8 Apr 2021 05:03:44 -0400
Subject: [PATCH] kvm: x86: protect masterclock with a seqcount
Protect the reference point for kvmclock with a seqcount, so that
kvmclock updates for all vCPUs can proceed in parallel. Xen runstate
updates will also run in parallel and not bounce the kvmclock cacheline.
This also makes it possible to use KVM_REQ_CLOCK_UPDATE (which will
block on the seqcount) to prevent entering in the guests until
pvclock_update_vm_gtod_copy is complete, and thus to get rid of
KVM_REQ_MCLOCK_INPROGRESS.
nr_vcpus_matched_tsc is updated outside pvclock_update_vm_gtod_copy
though, so a spinlock must be kept for that one.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
@@ -29,6 +29,8 @@ The acquisition orders for mutexes are as follows: On x86:+- the seqcount kvm->arch.pvclock_sc is written under kvm->lock.+- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock- kvm->arch.mmu_lock is an rwlock. kvm->arch.tdp_mmu_pages_lock is
@@ -2758,25 +2759,26 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)staticvoidkvm_start_pvclock_update(structkvm*kvm){structkvm_arch*ka=&kvm->arch;-kvm_make_all_cpus_request(kvm,KVM_REQ_MCLOCK_INPROGRESS);-/* no guest entries from this point */-spin_lock_irq(&ka->pvclock_gtod_sync_lock);+mutex_lock(&kvm->lock);+/*+*write_seqcount_begindisablespreemption.Thisisneedednotjust+*toavoidlivelock,butalsobecausethepreemptnotifierisareader+*forka->pvclock_sc.+*/+write_seqcount_begin(&ka->pvclock_sc);+kvm_make_all_cpus_request(kvm,+KVM_REQ_CLOCK_UPDATE|KVM_REQUEST_WAIT|KVM_REQUEST_NO_WAKEUP);++/* no guest entries from this point until write_seqcount_end */}staticvoidkvm_end_pvclock_update(structkvm*kvm){structkvm_arch*ka=&kvm->arch;-structkvm_vcpu*vcpu;-inti;-spin_unlock_irq(&ka->pvclock_gtod_sync_lock);-kvm_for_each_vcpu(i,vcpu,kvm)-kvm_make_request(KVM_REQ_CLOCK_UPDATE,vcpu);--/* guest entries allowed */-kvm_for_each_vcpu(i,vcpu,kvm)-kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS,vcpu);+write_seqcount_end(&ka->pvclock_sc);+mutex_unlock(&kvm->lock);}staticvoidkvm_update_masterclock(structkvm*kvm)
@@ -2787,27 +2789,21 @@ static void kvm_update_masterclock(struct kvm *kvm)kvm_end_pvclock_update(kvm);}-u64get_kvmclock_ns(structkvm*kvm)+staticu64__get_kvmclock_ns(structkvm*kvm){structkvm_arch*ka=&kvm->arch;structpvclock_vcpu_time_infohv_clock;-unsignedlongflags;u64ret;-spin_lock_irqsave(&ka->pvclock_gtod_sync_lock,flags);-if(!ka->use_master_clock){-spin_unlock_irqrestore(&ka->pvclock_gtod_sync_lock,flags);+if(!ka->use_master_clock)returnget_kvmclock_base_ns()+ka->kvmclock_offset;-}--hv_clock.tsc_timestamp=ka->master_cycle_now;-hv_clock.system_time=ka->master_kernel_ns+ka->kvmclock_offset;-spin_unlock_irqrestore(&ka->pvclock_gtod_sync_lock,flags);/* both __this_cpu_read() and rdtsc() should be on the same cpu */get_cpu();if(__this_cpu_read(cpu_tsc_khz)){+hv_clock.tsc_timestamp=ka->master_cycle_now;+hv_clock.system_time=ka->master_kernel_ns+ka->kvmclock_offset;kvm_get_time_scale(NSEC_PER_SEC,__this_cpu_read(cpu_tsc_khz)*1000LL,&hv_clock.tsc_shift,&hv_clock.tsc_to_system_mul);
@@ -2896,13 +2906,14 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)*IfthehostusesTSCclock,thenpassthroughTSCasstable*totheguest.*/-spin_lock_irqsave(&ka->pvclock_gtod_sync_lock,flags);-use_master_clock=ka->use_master_clock;-if(use_master_clock){-host_tsc=ka->master_cycle_now;-kernel_ns=ka->master_kernel_ns;-}-spin_unlock_irqrestore(&ka->pvclock_gtod_sync_lock,flags);+seq=read_seqcount_begin(&ka->pvclock_sc);+do{+use_master_clock=ka->use_master_clock;+if(use_master_clock){+host_tsc=ka->master_cycle_now;+kernel_ns=ka->master_kernel_ns;+}+}while(read_seqcount_retry(&ka->pvclock_sc,seq));/* Keep irq disabled to prevent changes to the clock */local_irq_save(flags);
@@ -6098,11 +6109,13 @@ long kvm_arch_vm_ioctl(struct file *filp,}caseKVM_GET_CLOCK:{structkvm_clock_datauser_ns;-u64now_ns;+unsignedseq;-now_ns=get_kvmclock_ns(kvm);-user_ns.clock=now_ns;-user_ns.flags=kvm->arch.use_master_clock?KVM_CLOCK_TSC_STABLE:0;+do{+seq=read_seqcount_begin(&kvm->arch.pvclock_sc);+user_ns.clock=__get_kvmclock_ns(kvm);+user_ns.flags=kvm->arch.use_master_clock?KVM_CLOCK_TSC_STABLE:0;+}while(read_seqcount_retry(&kvm->arch.pvclock_sc,seq));memset(&user_ns.pad,0,sizeof(user_ns.pad));r=-EFAULT;
@@ -11144,8 +11157,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)raw_spin_lock_init(&kvm->arch.tsc_write_lock);mutex_init(&kvm->arch.apic_map_lock);-spin_lock_init(&kvm->arch.pvclock_gtod_sync_lock);-+seqcount_mutex_init(&kvm->arch.pvclock_sc,&kvm->lock);kvm->arch.kvmclock_offset=-get_kvmclock_base_ns();pvclock_update_vm_gtod_copy(kvm);
This all looks good to me, so:
Reviewed-by: Oliver Upton <redacted>
Definitely supplants 03/21 from my series. If you'd rather take your
own for this entire series then I can rework around this patch and
resend.
--
Thanks,
Oliver
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2021-08-13 10:46:57
On 13/08/21 12:39, Oliver Upton wrote:
Might it make sense to fix this issue under the existing locking
scheme, then shift to what you're proposing? I say that, but the
locking change in 03/21 would most certainly have a short lifetime
until this patch supersedes it.
Yes, definitely. The seqcount change would definitely go in much later.
Extracting KVM_{GET,SET}_CLOCK to separate function would also be a
patch of its own. Give me a few more days of frantic KVM Forum
preparation. :)
Paolo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Oliver Upton <hidden> Date: 2021-08-13 17:48:40
On Fri, Aug 13, 2021 at 3:44 AM Paolo Bonzini [off-list ref] wrote:
On 13/08/21 12:39, Oliver Upton wrote:
quoted
Might it make sense to fix this issue under the existing locking
scheme, then shift to what you're proposing? I say that, but the
locking change in 03/21 would most certainly have a short lifetime
until this patch supersedes it.
Yes, definitely. The seqcount change would definitely go in much later.
Extracting KVM_{GET,SET}_CLOCK to separate function would also be a
patch of its own. Give me a few more days of frantic KVM Forum
preparation. :)
Sounds good :-) I'm probably going to send this out once more, in
three separate series:
- x86 (no changes, just rebasing)
- arm64 (address some comments, bugs)
- selftests (no changes)
--
Thanks,
Oliver