Skip to content

Commit a4b28f5

Browse files
author
Marc Zyngier
committed
Merge remote-tracking branch 'kvmarm/kvm-arm64/stolen-time' into kvmarm-master/next
2 parents da34517 + c7892db commit a4b28f5

File tree

36 files changed

+774
-207
lines changed

36 files changed

+774
-207
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3083,9 +3083,9 @@
30833083
[X86,PV_OPS] Disable paravirtualized VMware scheduler
30843084
clock and use the default one.
30853085

3086-
no-steal-acc [X86,KVM] Disable paravirtualized steal time accounting.
3087-
steal time is computed, but won't influence scheduler
3088-
behaviour
3086+
no-steal-acc [X86,KVM,ARM64] Disable paravirtualized steal time
3087+
accounting. steal time is computed, but won't
3088+
influence scheduler behaviour
30893089

30903090
nolapic [X86-32,APIC] Do not enable or use the local APIC.
30913091

Documentation/virt/kvm/arm/pvtime.rst

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
Paravirtualized time support for arm64
4+
======================================
5+
6+
Arm specification DEN0057/A defines a standard for paravirtualised time
7+
support for AArch64 guests:
8+
9+
https://developer.arm.com/docs/den0057/a
10+
11+
KVM/arm64 implements the stolen time part of this specification by providing
12+
some hypervisor service calls to support a paravirtualized guest obtaining a
13+
view of the amount of time stolen from its execution.
14+
15+
Two new SMCCC compatible hypercalls are defined:
16+
17+
* PV_TIME_FEATURES: 0xC5000020
18+
* PV_TIME_ST: 0xC5000021
19+
20+
These are only available in the SMC64/HVC64 calling convention as
21+
paravirtualized time is not available to 32 bit Arm guests. The existence of
22+
the PV_FEATURES hypercall should be probed using the SMCCC 1.1 ARCH_FEATURES
23+
mechanism before calling it.
24+
25+
PV_TIME_FEATURES
26+
============= ======== ==========
27+
Function ID: (uint32) 0xC5000020
28+
PV_call_id: (uint32) The function to query for support.
29+
Currently only PV_TIME_ST is supported.
30+
Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if the relevant
31+
PV-time feature is supported by the hypervisor.
32+
============= ======== ==========
33+
34+
PV_TIME_ST
35+
============= ======== ==========
36+
Function ID: (uint32) 0xC5000021
37+
Return value: (int64) IPA of the stolen time data structure for this
38+
VCPU. On failure:
39+
NOT_SUPPORTED (-1)
40+
============= ======== ==========
41+
42+
The IPA returned by PV_TIME_ST should be mapped by the guest as normal memory
43+
with inner and outer write back caching attributes, in the inner shareable
44+
domain. A total of 16 bytes from the IPA returned are guaranteed to be
45+
meaningfully filled by the hypervisor (see structure below).
46+
47+
PV_TIME_ST returns the structure for the calling VCPU.
48+
49+
Stolen Time
50+
-----------
51+
52+
The structure pointed to by the PV_TIME_ST hypercall is as follows:
53+
54+
+-------------+-------------+-------------+----------------------------+
55+
| Field | Byte Length | Byte Offset | Description |
56+
+=============+=============+=============+============================+
57+
| Revision | 4 | 0 | Must be 0 for version 1.0 |
58+
+-------------+-------------+-------------+----------------------------+
59+
| Attributes | 4 | 4 | Must be 0 |
60+
+-------------+-------------+-------------+----------------------------+
61+
| Stolen time | 8 | 8 | Stolen time in unsigned |
62+
| | | | nanoseconds indicating how |
63+
| | | | much time this VCPU thread |
64+
| | | | was involuntarily not |
65+
| | | | running on a physical CPU. |
66+
+-------------+-------------+-------------+----------------------------+
67+
68+
All values in the structure are stored little-endian.
69+
70+
The structure will be updated by the hypervisor prior to scheduling a VCPU. It
71+
will be present within a reserved region of the normal memory given to the
72+
guest. The guest should not attempt to write into this memory. There is a
73+
structure per VCPU of the guest.
74+
75+
It is advisable that one or more 64k pages are set aside for the purpose of
76+
these structures and not used for other purposes, this enables the guest to map
77+
the region using 64k pages and avoids conflicting attributes with other memory.
78+
79+
For the user space interface see Documentation/virt/kvm/devices/vcpu.txt
80+
section "3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL".

Documentation/virt/kvm/devices/vcpu.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,17 @@ time to use the number provided for a given timer, overwriting any previously
6060
configured values on other VCPUs. Userspace should configure the interrupt
6161
numbers on at least one VCPU after creating all VCPUs and before running any
6262
VCPUs.
63+
64+
3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL
65+
Architectures: ARM64
66+
67+
3.1 ATTRIBUTE: KVM_ARM_VCPU_PVTIME_IPA
68+
Parameters: 64-bit base address
69+
Returns: -ENXIO: Stolen time not implemented
70+
-EEXIST: Base address already set for this VCPU
71+
-EINVAL: Base address not 64 byte aligned
72+
73+
Specifies the base address of the stolen time structure for this VCPU. The
74+
base address must be 64 byte aligned and exist within a valid guest memory
75+
region. See Documentation/virt/kvm/arm/pvtime.txt for more information
76+
including the layout of the stolen time structure.

arch/arm/include/asm/kvm_host.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef __ARM_KVM_HOST_H__
88
#define __ARM_KVM_HOST_H__
99

10+
#include <linux/arm-smccc.h>
1011
#include <linux/errno.h>
1112
#include <linux/types.h>
1213
#include <linux/kvm_types.h>
@@ -38,6 +39,7 @@
3839
KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
3940
#define KVM_REQ_IRQ_PENDING KVM_ARCH_REQ(1)
4041
#define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(2)
42+
#define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(3)
4143

4244
DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
4345

@@ -331,6 +333,29 @@ static inline int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
331333
int kvm_perf_init(void);
332334
int kvm_perf_teardown(void);
333335

336+
static inline long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu)
337+
{
338+
return SMCCC_RET_NOT_SUPPORTED;
339+
}
340+
341+
static inline gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu)
342+
{
343+
return GPA_INVALID;
344+
}
345+
346+
static inline void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
347+
{
348+
}
349+
350+
static inline void kvm_arm_pvtime_vcpu_init(struct kvm_vcpu_arch *vcpu_arch)
351+
{
352+
}
353+
354+
static inline bool kvm_arm_is_pvtime_enabled(struct kvm_vcpu_arch *vcpu_arch)
355+
{
356+
return false;
357+
}
358+
334359
void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
335360

336361
struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);

arch/arm/kvm/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ obj-y += kvm-arm.o init.o interrupts.o
2424
obj-y += handle_exit.o guest.o emulate.o reset.o
2525
obj-y += coproc.o coproc_a15.o coproc_a7.o vgic-v3-coproc.o
2626
obj-y += $(KVM)/arm/arm.o $(KVM)/arm/mmu.o $(KVM)/arm/mmio.o
27-
obj-y += $(KVM)/arm/psci.o $(KVM)/arm/perf.o
27+
obj-y += $(KVM)/arm/psci.o $(KVM)/arm/perf.o $(KVM)/arm/hypercalls.o
2828
obj-y += $(KVM)/arm/aarch32.o
2929

3030
obj-y += $(KVM)/arm/vgic/vgic.o

arch/arm/kvm/handle_exit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <asm/kvm_emulate.h>
1010
#include <asm/kvm_coproc.h>
1111
#include <asm/kvm_mmu.h>
12-
#include <kvm/arm_psci.h>
12+
#include <kvm/arm_hypercalls.h>
1313
#include <trace/events/kvm.h>
1414

1515
#include "trace.h"

arch/arm/mm/proc-v7-bugs.c

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22
#include <linux/arm-smccc.h>
33
#include <linux/kernel.h>
4-
#include <linux/psci.h>
54
#include <linux/smp.h>
65

76
#include <asm/cp15.h>
@@ -75,26 +74,20 @@ static void cpu_v7_spectre_init(void)
7574
case ARM_CPU_PART_CORTEX_A72: {
7675
struct arm_smccc_res res;
7776

78-
if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
79-
break;
77+
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
78+
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
79+
if ((int)res.a0 != 0)
80+
return;
8081

81-
switch (psci_ops.conduit) {
82-
case PSCI_CONDUIT_HVC:
83-
arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
84-
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
85-
if ((int)res.a0 != 0)
86-
break;
82+
switch (arm_smccc_1_1_get_conduit()) {
83+
case SMCCC_CONDUIT_HVC:
8784
per_cpu(harden_branch_predictor_fn, cpu) =
8885
call_hvc_arch_workaround_1;
8986
cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
9087
spectre_v2_method = "hypervisor";
9188
break;
9289

93-
case PSCI_CONDUIT_SMC:
94-
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
95-
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
96-
if ((int)res.a0 != 0)
97-
break;
90+
case SMCCC_CONDUIT_SMC:
9891
per_cpu(harden_branch_predictor_fn, cpu) =
9992
call_smc_arch_workaround_1;
10093
cpu_do_switch_mm = cpu_v7_smc_switch_mm;

arch/arm64/include/asm/kvm_host.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
4545
#define KVM_REQ_IRQ_PENDING KVM_ARCH_REQ(1)
4646
#define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(2)
47+
#define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(3)
4748

4849
DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
4950

@@ -346,6 +347,13 @@ struct kvm_vcpu_arch {
346347
/* True when deferrable sysregs are loaded on the physical CPU,
347348
* see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
348349
bool sysregs_loaded_on_cpu;
350+
351+
/* Guest PV state */
352+
struct {
353+
u64 steal;
354+
u64 last_steal;
355+
gpa_t base;
356+
} steal;
349357
};
350358

351359
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
@@ -486,6 +494,27 @@ void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
486494
int kvm_perf_init(void);
487495
int kvm_perf_teardown(void);
488496

497+
long kvm_hypercall_pv_features(struct kvm_vcpu *vcpu);
498+
gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu);
499+
void kvm_update_stolen_time(struct kvm_vcpu *vcpu);
500+
501+
int kvm_arm_pvtime_set_attr(struct kvm_vcpu *vcpu,
502+
struct kvm_device_attr *attr);
503+
int kvm_arm_pvtime_get_attr(struct kvm_vcpu *vcpu,
504+
struct kvm_device_attr *attr);
505+
int kvm_arm_pvtime_has_attr(struct kvm_vcpu *vcpu,
506+
struct kvm_device_attr *attr);
507+
508+
static inline void kvm_arm_pvtime_vcpu_init(struct kvm_vcpu_arch *vcpu_arch)
509+
{
510+
vcpu_arch->steal.base = GPA_INVALID;
511+
}
512+
513+
static inline bool kvm_arm_is_pvtime_enabled(struct kvm_vcpu_arch *vcpu_arch)
514+
{
515+
return (vcpu_arch->steal.base != GPA_INVALID);
516+
}
517+
489518
void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
490519

491520
struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);

arch/arm64/include/asm/paravirt.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ static inline u64 paravirt_steal_clock(int cpu)
2121
{
2222
return pv_ops.time.steal_clock(cpu);
2323
}
24-
#endif
24+
25+
int __init pv_time_init(void);
26+
27+
#else
28+
29+
#define pv_time_init() do {} while (0)
30+
31+
#endif // CONFIG_PARAVIRT
2532

2633
#endif

arch/arm64/include/asm/pvclock-abi.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (C) 2019 Arm Ltd. */
3+
4+
#ifndef __ASM_PVCLOCK_ABI_H
5+
#define __ASM_PVCLOCK_ABI_H
6+
7+
/* The below structure is defined in ARM DEN0057A */
8+
9+
struct pvclock_vcpu_stolen_time {
10+
__le32 revision;
11+
__le32 attributes;
12+
__le64 stolen_time;
13+
/* Structure must be 64 byte aligned, pad to that size */
14+
u8 padding[48];
15+
} __packed;
16+
17+
#endif

0 commit comments

Comments
 (0)