* kvm-arm64/hcall-selection: : . : Introduce a new set of virtual sysregs for userspace to : select the hypercalls it wants to see exposed to the guest. : : Patches courtesy of Raghavendra and Oliver. : . KVM: arm64: Fix hypercall bitmap writeback when vcpus have already run KVM: arm64: Hide KVM_REG_ARM_*_BMAP_BIT_COUNT from userspace Documentation: Fix index.rst after psci.rst renaming selftests: KVM: aarch64: Add the bitmap firmware registers to get-reg-list selftests: KVM: aarch64: Introduce hypercall ABI test selftests: KVM: Create helper for making SMCCC calls selftests: KVM: Rename psci_cpu_on_test to psci_test tools: Import ARM SMCCC definitions Docs: KVM: Add doc for the bitmap firmware registers Docs: KVM: Rename psci.rst to hypercalls.rst KVM: arm64: Add vendor hypervisor firmware register KVM: arm64: Add standard hypervisor firmware register KVM: arm64: Setup a framework for hypercall bitmap firmware registers KVM: arm64: Factor out firmware register handling from psci.c
Unified · Split
| @@ -2601,6 +2601,24 @@ EINVAL. · 2600 unmodified lines | ||
| 2601 | 2601 | After the vcpu's SVE configuration is finalized, further attempts to |
| 2602 | 2602 | write this register will fail with EPERM. |
| 2603 | 2603 | |
| 2604 | +arm64 bitmap feature firmware pseudo-registers have the following bit pattern:: | |
| 2605 | + | |
| 2606 | + 0x6030 0000 0016 <regno:16> | |
| 2607 | + | |
| 2608 | +The bitmap feature firmware registers exposes the hypercall services that | |
| 2609 | +are available for userspace to configure. The set bits corresponds to the | |
| 2610 | +services that are available for the guests to access. By default, KVM | |
| 2611 | +sets all the supported bits during VM initialization. The userspace can | |
| 2612 | +discover the available services via KVM_GET_ONE_REG, and write back the | |
| 2613 | +bitmap corresponding to the features that it wishes guests to see via | |
| 2614 | +KVM_SET_ONE_REG. | |
| 2615 | + | |
| 2616 | +Note: These registers are immutable once any of the vCPUs of the VM has | |
| 2617 | +run at least once. A KVM_SET_ONE_REG in such a scenario will return | |
| 2618 | +a -EBUSY to userspace. | |
| 2619 | + | |
| 2620 | +(See Documentation/virt/kvm/arm/hypercalls.rst for more details.) | |
| 2621 | + | |
| 2604 | 2622 | |
| 2605 | 2623 | MIPS registers are mapped using the lower 32 bits. The upper 16 of that is |
| 2606 | 2624 | the register group type: |
| @@ -0,0 +1,138 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +======================= | |
| 4 | +ARM Hypercall Interface | |
| 5 | +======================= | |
| 6 | + | |
| 7 | +KVM handles the hypercall services as requested by the guests. New hypercall | |
| 8 | +services are regularly made available by the ARM specification or by KVM (as | |
| 9 | +vendor services) if they make sense from a virtualization point of view. | |
| 10 | + | |
| 11 | +This means that a guest booted on two different versions of KVM can observe | |
| 12 | +two different "firmware" revisions. This could cause issues if a given guest | |
| 13 | +is tied to a particular version of a hypercall service, or if a migration | |
| 14 | +causes a different version to be exposed out of the blue to an unsuspecting | |
| 15 | +guest. | |
| 16 | + | |
| 17 | +In order to remedy this situation, KVM exposes a set of "firmware | |
| 18 | +pseudo-registers" that can be manipulated using the GET/SET_ONE_REG | |
| 19 | +interface. These registers can be saved/restored by userspace, and set | |
| 20 | +to a convenient value as required. | |
| 21 | + | |
| 22 | +The following registers are defined: | |
| 23 | + | |
| 24 | +* KVM_REG_ARM_PSCI_VERSION: | |
| 25 | + | |
| 26 | + KVM implements the PSCI (Power State Coordination Interface) | |
| 27 | + specification in order to provide services such as CPU on/off, reset | |
| 28 | + and power-off to the guest. | |
| 29 | + | |
| 30 | + - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set | |
| 31 | + (and thus has already been initialized) | |
| 32 | + - Returns the current PSCI version on GET_ONE_REG (defaulting to the | |
| 33 | + highest PSCI version implemented by KVM and compatible with v0.2) | |
| 34 | + - Allows any PSCI version implemented by KVM and compatible with | |
| 35 | + v0.2 to be set with SET_ONE_REG | |
| 36 | + - Affects the whole VM (even if the register view is per-vcpu) | |
| 37 | + | |
| 38 | +* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 39 | + Holds the state of the firmware support to mitigate CVE-2017-5715, as | |
| 40 | + offered by KVM to the guest via a HVC call. The workaround is described | |
| 41 | + under SMCCC_ARCH_WORKAROUND_1 in [1]. | |
| 42 | + | |
| 43 | + Accepted values are: | |
| 44 | + | |
| 45 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL: | |
| 46 | + KVM does not offer | |
| 47 | + firmware support for the workaround. The mitigation status for the | |
| 48 | + guest is unknown. | |
| 49 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL: | |
| 50 | + The workaround HVC call is | |
| 51 | + available to the guest and required for the mitigation. | |
| 52 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED: | |
| 53 | + The workaround HVC call | |
| 54 | + is available to the guest, but it is not needed on this VCPU. | |
| 55 | + | |
| 56 | +* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 57 | + Holds the state of the firmware support to mitigate CVE-2018-3639, as | |
| 58 | + offered by KVM to the guest via a HVC call. The workaround is described | |
| 59 | + under SMCCC_ARCH_WORKAROUND_2 in [1]_. | |
| 60 | + | |
| 61 | + Accepted values are: | |
| 62 | + | |
| 63 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: | |
| 64 | + A workaround is not | |
| 65 | + available. KVM does not offer firmware support for the workaround. | |
| 66 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: | |
| 67 | + The workaround state is | |
| 68 | + unknown. KVM does not offer firmware support for the workaround. | |
| 69 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: | |
| 70 | + The workaround is available, | |
| 71 | + and can be disabled by a vCPU. If | |
| 72 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED is set, it is active for | |
| 73 | + this vCPU. | |
| 74 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: | |
| 75 | + The workaround is always active on this vCPU or it is not needed. | |
| 76 | + | |
| 77 | + | |
| 78 | +Bitmap Feature Firmware Registers | |
| 79 | +--------------------------------- | |
| 80 | + | |
| 81 | +Contrary to the above registers, the following registers exposes the | |
| 82 | +hypercall services in the form of a feature-bitmap to the userspace. This | |
| 83 | +bitmap is translated to the services that are available to the guest. | |
| 84 | +There is a register defined per service call owner and can be accessed via | |
| 85 | +GET/SET_ONE_REG interface. | |
| 86 | + | |
| 87 | +By default, these registers are set with the upper limit of the features | |
| 88 | +that are supported. This way userspace can discover all the usable | |
| 89 | +hypercall services via GET_ONE_REG. The user-space can write-back the | |
| 90 | +desired bitmap back via SET_ONE_REG. The features for the registers that | |
| 91 | +are untouched, probably because userspace isn't aware of them, will be | |
| 92 | +exposed as is to the guest. | |
| 93 | + | |
| 94 | +Note that KVM will not allow the userspace to configure the registers | |
| 95 | +anymore once any of the vCPUs has run at least once. Instead, it will | |
| 96 | +return a -EBUSY. | |
| 97 | + | |
| 98 | +The pseudo-firmware bitmap register are as follows: | |
| 99 | + | |
| 100 | +* KVM_REG_ARM_STD_BMAP: | |
| 101 | + Controls the bitmap of the ARM Standard Secure Service Calls. | |
| 102 | + | |
| 103 | + The following bits are accepted: | |
| 104 | + | |
| 105 | + Bit-0: KVM_REG_ARM_STD_BIT_TRNG_V1_0: | |
| 106 | + The bit represents the services offered under v1.0 of ARM True Random | |
| 107 | + Number Generator (TRNG) specification, ARM DEN0098. | |
| 108 | + | |
| 109 | +* KVM_REG_ARM_STD_HYP_BMAP: | |
| 110 | + Controls the bitmap of the ARM Standard Hypervisor Service Calls. | |
| 111 | + | |
| 112 | + The following bits are accepted: | |
| 113 | + | |
| 114 | + Bit-0: KVM_REG_ARM_STD_HYP_BIT_PV_TIME: | |
| 115 | + The bit represents the Paravirtualized Time service as represented by | |
| 116 | + ARM DEN0057A. | |
| 117 | + | |
| 118 | +* KVM_REG_ARM_VENDOR_HYP_BMAP: | |
| 119 | + Controls the bitmap of the Vendor specific Hypervisor Service Calls. | |
| 120 | + | |
| 121 | + The following bits are accepted: | |
| 122 | + | |
| 123 | + Bit-0: KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT | |
| 124 | + The bit represents the ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID | |
| 125 | + and ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID function-ids. | |
| 126 | + | |
| 127 | + Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP: | |
| 128 | + The bit represents the Precision Time Protocol KVM service. | |
| 129 | + | |
| 130 | +Errors: | |
| 131 | + | |
| 132 | + ======= ============================================================= | |
| 133 | + -ENOENT Unknown register accessed. | |
| 134 | + -EBUSY Attempt a 'write' to the register after the VM has started. | |
| 135 | + -EINVAL Invalid bitmap written to the register. | |
| 136 | + ======= ============================================================= | |
| 137 | + | |
| 138 | +.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf | |
| @@ -8,6 +8,6 @@ ARM · 7 unmodified lines | ||
| 8 | 8 | :maxdepth: 2 |
| 9 | 9 | |
| 10 | 10 | hyp-abi |
| 11 | − psci | |
| 11 | + hypercalls | |
| 12 | 12 | pvtime |
| 13 | 13 | ptp_kvm |
| @@ -1,77 +0,0 @@ | ||
| 1 | −.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | − | |
| 3 | −========================================= | |
| 4 | −Power State Coordination Interface (PSCI) | |
| 5 | −========================================= | |
| 6 | − | |
| 7 | −KVM implements the PSCI (Power State Coordination Interface) | |
| 8 | −specification in order to provide services such as CPU on/off, reset | |
| 9 | −and power-off to the guest. | |
| 10 | − | |
| 11 | −The PSCI specification is regularly updated to provide new features, | |
| 12 | −and KVM implements these updates if they make sense from a virtualization | |
| 13 | −point of view. | |
| 14 | − | |
| 15 | −This means that a guest booted on two different versions of KVM can | |
| 16 | −observe two different "firmware" revisions. This could cause issues if | |
| 17 | −a given guest is tied to a particular PSCI revision (unlikely), or if | |
| 18 | −a migration causes a different PSCI version to be exposed out of the | |
| 19 | −blue to an unsuspecting guest. | |
| 20 | − | |
| 21 | −In order to remedy this situation, KVM exposes a set of "firmware | |
| 22 | −pseudo-registers" that can be manipulated using the GET/SET_ONE_REG | |
| 23 | −interface. These registers can be saved/restored by userspace, and set | |
| 24 | −to a convenient value if required. | |
| 25 | − | |
| 26 | −The following register is defined: | |
| 27 | − | |
| 28 | −* KVM_REG_ARM_PSCI_VERSION: | |
| 29 | − | |
| 30 | − - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set | |
| 31 | − (and thus has already been initialized) | |
| 32 | − - Returns the current PSCI version on GET_ONE_REG (defaulting to the | |
| 33 | − highest PSCI version implemented by KVM and compatible with v0.2) | |
| 34 | − - Allows any PSCI version implemented by KVM and compatible with | |
| 35 | − v0.2 to be set with SET_ONE_REG | |
| 36 | − - Affects the whole VM (even if the register view is per-vcpu) | |
| 37 | − | |
| 38 | −* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 39 | − Holds the state of the firmware support to mitigate CVE-2017-5715, as | |
| 40 | − offered by KVM to the guest via a HVC call. The workaround is described | |
| 41 | − under SMCCC_ARCH_WORKAROUND_1 in [1]. | |
| 42 | − | |
| 43 | − Accepted values are: | |
| 44 | − | |
| 45 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL: | |
| 46 | − KVM does not offer | |
| 47 | − firmware support for the workaround. The mitigation status for the | |
| 48 | − guest is unknown. | |
| 49 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL: | |
| 50 | − The workaround HVC call is | |
| 51 | − available to the guest and required for the mitigation. | |
| 52 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED: | |
| 53 | − The workaround HVC call | |
| 54 | − is available to the guest, but it is not needed on this VCPU. | |
| 55 | − | |
| 56 | −* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 57 | − Holds the state of the firmware support to mitigate CVE-2018-3639, as | |
| 58 | − offered by KVM to the guest via a HVC call. The workaround is described | |
| 59 | − under SMCCC_ARCH_WORKAROUND_2 in [1]_. | |
| 60 | − | |
| 61 | − Accepted values are: | |
| 62 | − | |
| 63 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: | |
| 64 | − A workaround is not | |
| 65 | − available. KVM does not offer firmware support for the workaround. | |
| 66 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: | |
| 67 | − The workaround state is | |
| 68 | − unknown. KVM does not offer firmware support for the workaround. | |
| 69 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: | |
| 70 | − The workaround is available, | |
| 71 | − and can be disabled by a vCPU. If | |
| 72 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED is set, it is active for | |
| 73 | − this vCPU. | |
| 74 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: | |
| 75 | − The workaround is always active on this vCPU or it is not needed. | |
| 76 | − | |
| 77 | −.. [1] https://developer.arm.com/-/media/developer/pdf/ARM_DEN_0070A_Firmware_interfaces_for_mitigating_CVE-2017-5715.pdf | |
| @@ -101,6 +101,19 @@ struct kvm_s2_mmu { · 100 unmodified lines | ||
| 101 | 101 | struct kvm_arch_memory_slot { |
| 102 | 102 | }; |
| 103 | 103 | |
| 104 | +/** | |
| 105 | + * struct kvm_smccc_features: Descriptor of the hypercall services exposed to the guests | |
| 106 | + * | |
| 107 | + * @std_bmap: Bitmap of standard secure service calls | |
| 108 | + * @std_hyp_bmap: Bitmap of standard hypervisor service calls | |
| 109 | + * @vendor_hyp_bmap: Bitmap of vendor specific hypervisor service calls | |
| 110 | + */ | |
| 111 | +struct kvm_smccc_features { | |
| 112 | + unsigned long std_bmap; | |
| 113 | + unsigned long std_hyp_bmap; | |
| 114 | + unsigned long vendor_hyp_bmap; | |
| 115 | +}; | |
| 116 | + | |
| 104 | 117 | struct kvm_arch { |
| 105 | 118 | struct kvm_s2_mmu mmu; |
| 106 | 119 | |
| @@ -150,6 +163,9 @@ struct kvm_arch { · 43 unmodified lines | ||
| 150 | 163 | |
| 151 | 164 | u8 pfr0_csv2; |
| 152 | 165 | u8 pfr0_csv3; |
| 166 | + | |
| 167 | + /* Hypercall features firmware registers' descriptor */ | |
| 168 | + struct kvm_smccc_features smccc_feat; | |
| 153 | 169 | }; |
| 154 | 170 | |
| 155 | 171 | struct kvm_vcpu_fault_info { |
| @@ -332,6 +332,40 @@ struct kvm_arm_copy_mte_tags { · 331 unmodified lines | ||
| 332 | 332 | #define KVM_ARM64_SVE_VLS_WORDS \ |
| 333 | 333 | ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1) |
| 334 | 334 | |
| 335 | +/* Bitmap feature firmware registers */ | |
| 336 | +#define KVM_REG_ARM_FW_FEAT_BMAP (0x0016 << KVM_REG_ARM_COPROC_SHIFT) | |
| 337 | +#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ | |
| 338 | + KVM_REG_ARM_FW_FEAT_BMAP | \ | |
| 339 | + ((r) & 0xffff)) | |
| 340 | + | |
| 341 | +#define KVM_REG_ARM_STD_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(0) | |
| 342 | + | |
| 343 | +enum { | |
| 344 | + KVM_REG_ARM_STD_BIT_TRNG_V1_0 = 0, | |
| 345 | +#ifdef __KERNEL__ | |
| 346 | + KVM_REG_ARM_STD_BMAP_BIT_COUNT, | |
| 347 | +#endif | |
| 348 | +}; | |
| 349 | + | |
| 350 | +#define KVM_REG_ARM_STD_HYP_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(1) | |
| 351 | + | |
| 352 | +enum { | |
| 353 | + KVM_REG_ARM_STD_HYP_BIT_PV_TIME = 0, | |
| 354 | +#ifdef __KERNEL__ | |
| 355 | + KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT, | |
| 356 | +#endif | |
| 357 | +}; | |
| 358 | + | |
| 359 | +#define KVM_REG_ARM_VENDOR_HYP_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(2) | |
| 360 | + | |
| 361 | +enum { | |
| 362 | + KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT = 0, | |
| 363 | + KVM_REG_ARM_VENDOR_HYP_BIT_PTP = 1, | |
| 364 | +#ifdef __KERNEL__ | |
| 365 | + KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT, | |
| 366 | +#endif | |
| 367 | +}; | |
| 368 | + | |
| 335 | 369 | /* Device Control API: ARM VGIC */ |
| 336 | 370 | #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 |
| 337 | 371 | #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 |
| @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) · 155 unmodified lines | ||
| 156 | 156 | kvm->arch.max_vcpus = kvm_arm_default_max_vcpus(); |
| 157 | 157 | |
| 158 | 158 | set_default_spectre(kvm); |
| 159 | + kvm_arm_init_hypercalls(kvm); | |
| 159 | 160 | |
| 160 | 161 | return ret; |
| 161 | 162 | out_free_stage2_pgd: |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/string.h> |
| 19 | 19 | #include <linux/vmalloc.h> |
| 20 | 20 | #include <linux/fs.h> |
| 21 | −#include <kvm/arm_psci.h> | |
| 21 | +#include <kvm/arm_hypercalls.h> | |
| 22 | 22 | #include <asm/cputype.h> |
| 23 | 23 | #include <linux/uaccess.h> |
| 24 | 24 | #include <asm/fpsimd.h> |
| @@ -756,7 +756,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) · 731 unmodified lines | ||
| 756 | 756 | |
| 757 | 757 | switch (reg->id & KVM_REG_ARM_COPROC_MASK) { |
| 758 | 758 | case KVM_REG_ARM_CORE: return get_core_reg(vcpu, reg); |
| 759 | − case KVM_REG_ARM_FW: return kvm_arm_get_fw_reg(vcpu, reg); | |
| 759 | + case KVM_REG_ARM_FW: | |
| 760 | + case KVM_REG_ARM_FW_FEAT_BMAP: | |
| 761 | + return kvm_arm_get_fw_reg(vcpu, reg); | |
| 760 | 762 | case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg); |
| 761 | 763 | } |
| 762 | 764 | |
| @@ -774,7 +776,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) · 11 unmodified lines | ||
| 774 | 776 | |
| 775 | 777 | switch (reg->id & KVM_REG_ARM_COPROC_MASK) { |
| 776 | 778 | case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg); |
| 777 | − case KVM_REG_ARM_FW: return kvm_arm_set_fw_reg(vcpu, reg); | |
| 779 | + case KVM_REG_ARM_FW: | |
| 780 | + case KVM_REG_ARM_FW_FEAT_BMAP: | |
| 781 | + return kvm_arm_set_fw_reg(vcpu, reg); | |
| 778 | 782 | case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg); |
| 779 | 783 | } |
| 780 | 784 | |
| @@ -9,6 +9,13 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <kvm/arm_hypercalls.h> |
| 10 | 10 | #include <kvm/arm_psci.h> |
| 11 | 11 | |
| 12 | +#define KVM_ARM_SMCCC_STD_FEATURES \ | |
| 13 | + GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0) | |
| 14 | +#define KVM_ARM_SMCCC_STD_HYP_FEATURES \ | |
| 15 | + GENMASK(KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT - 1, 0) | |
| 16 | +#define KVM_ARM_SMCCC_VENDOR_HYP_FEATURES \ | |
| 17 | + GENMASK(KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT - 1, 0) | |
| 18 | + | |
| 12 | 19 | static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) |
| 13 | 20 | { |
| 14 | 21 | struct system_time_snapshot systime_snapshot; |
| @@ -58,13 +65,73 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) · 43 unmodified lines | ||
| 58 | 65 | val[3] = lower_32_bits(cycles); |
| 59 | 66 | } |
| 60 | 67 | |
| 68 | +static bool kvm_hvc_call_default_allowed(u32 func_id) | |
| 69 | +{ | |
| 70 | + switch (func_id) { | |
| 71 | + /* | |
| 72 | + * List of function-ids that are not gated with the bitmapped | |
| 73 | + * feature firmware registers, and are to be allowed for | |
| 74 | + * servicing the call by default. | |
| 75 | + */ | |
| 76 | + case ARM_SMCCC_VERSION_FUNC_ID: | |
| 77 | + case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: | |
| 78 | + return true; | |
| 79 | + default: | |
| 80 | + /* PSCI 0.2 and up is in the 0:0x1f range */ | |
| 81 | + if (ARM_SMCCC_OWNER_NUM(func_id) == ARM_SMCCC_OWNER_STANDARD && | |
| 82 | + ARM_SMCCC_FUNC_NUM(func_id) <= 0x1f) | |
| 83 | + return true; | |
| 84 | + | |
| 85 | + /* | |
| 86 | + * KVM's PSCI 0.1 doesn't comply with SMCCC, and has | |
| 87 | + * its own function-id base and range | |
| 88 | + */ | |
| 89 | + if (func_id >= KVM_PSCI_FN(0) && func_id <= KVM_PSCI_FN(3)) | |
| 90 | + return true; | |
| 91 | + | |
| 92 | + return false; | |
| 93 | + } | |
| 94 | +} | |
| 95 | + | |
| 96 | +static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) | |
| 97 | +{ | |
| 98 | + struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; | |
| 99 | + | |
| 100 | + switch (func_id) { | |
| 101 | + case ARM_SMCCC_TRNG_VERSION: | |
| 102 | + case ARM_SMCCC_TRNG_FEATURES: | |
| 103 | + case ARM_SMCCC_TRNG_GET_UUID: | |
| 104 | + case ARM_SMCCC_TRNG_RND32: | |
| 105 | + case ARM_SMCCC_TRNG_RND64: | |
| 106 | + return test_bit(KVM_REG_ARM_STD_BIT_TRNG_V1_0, | |
| 107 | + &smccc_feat->std_bmap); | |
| 108 | + case ARM_SMCCC_HV_PV_TIME_FEATURES: | |
| 109 | + case ARM_SMCCC_HV_PV_TIME_ST: | |
| 110 | + return test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, | |
| 111 | + &smccc_feat->std_hyp_bmap); | |
| 112 | + case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: | |
| 113 | + case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: | |
| 114 | + return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT, | |
| 115 | + &smccc_feat->vendor_hyp_bmap); | |
| 116 | + case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: | |
| 117 | + return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP, | |
| 118 | + &smccc_feat->vendor_hyp_bmap); | |
| 119 | + default: | |
| 120 | + return kvm_hvc_call_default_allowed(func_id); | |
| 121 | + } | |
| 122 | +} | |
| 123 | + | |
| 61 | 124 | int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) |
| 62 | 125 | { |
| 126 | + struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; | |
| 63 | 127 | u32 func_id = smccc_get_function(vcpu); |
| 64 | 128 | u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; |
| 65 | 129 | u32 feature; |
| 66 | 130 | gpa_t gpa; |
| 67 | 131 | |
| 132 | + if (!kvm_hvc_call_allowed(vcpu, func_id)) | |
| 133 | + goto out; | |
| 134 | + | |
| 68 | 135 | switch (func_id) { |
| 69 | 136 | case ARM_SMCCC_VERSION_FUNC_ID: |
| 70 | 137 | val[0] = ARM_SMCCC_VERSION_1_1; |
| @@ -120,7 +187,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) · 49 unmodified lines | ||
| 120 | 187 | } |
| 121 | 188 | break; |
| 122 | 189 | case ARM_SMCCC_HV_PV_TIME_FEATURES: |
| 123 | − val[0] = SMCCC_RET_SUCCESS; | |
| 190 | + if (test_bit(KVM_REG_ARM_STD_HYP_BIT_PV_TIME, | |
| 191 | + &smccc_feat->std_hyp_bmap)) | |
| 192 | + val[0] = SMCCC_RET_SUCCESS; | |
| 124 | 193 | break; |
| 125 | 194 | } |
| 126 | 195 | break; |
| @@ -139,8 +208,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) · 12 unmodified lines | ||
| 139 | 208 | val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; |
| 140 | 209 | break; |
| 141 | 210 | case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: |
| 142 | − val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES); | |
| 143 | − val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP); | |
| 211 | + val[0] = smccc_feat->vendor_hyp_bmap; | |
| 144 | 212 | break; |
| 145 | 213 | case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: |
| 146 | 214 | kvm_ptp_get_time(vcpu, val); |
| @@ -155,6 +223,259 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) · 8 unmodified lines | ||
| 155 | 223 | return kvm_psci_call(vcpu); |
| 156 | 224 | } |
| 157 | 225 | |
| 226 | +out: | |
| 158 | 227 | smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); |
| 159 | 228 | return 1; |
| 160 | 229 | } |
| 230 | + | |
| 231 | +static const u64 kvm_arm_fw_reg_ids[] = { | |
| 232 | + KVM_REG_ARM_PSCI_VERSION, | |
| 233 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, | |
| 234 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, | |
| 235 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, | |
| 236 | + KVM_REG_ARM_STD_BMAP, | |
| 237 | + KVM_REG_ARM_STD_HYP_BMAP, | |
| 238 | + KVM_REG_ARM_VENDOR_HYP_BMAP, | |
| 239 | +}; | |
| 240 | + | |
| 241 | +void kvm_arm_init_hypercalls(struct kvm *kvm) | |
| 242 | +{ | |
| 243 | + struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; | |
| 244 | + | |
| 245 | + smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; | |
| 246 | + smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; | |
| 247 | + smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; | |
| 248 | +} | |
| 249 | + | |
| 250 | +int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) | |
| 251 | +{ | |
| 252 | + return ARRAY_SIZE(kvm_arm_fw_reg_ids); | |
| 253 | +} | |
| 254 | + | |
| 255 | +int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) | |
| 256 | +{ | |
| 257 | + int i; | |
| 258 | + | |
| 259 | + for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { | |
| 260 | + if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) | |
| 261 | + return -EFAULT; | |
| 262 | + } | |
| 263 | + | |
| 264 | + return 0; | |
| 265 | +} | |
| 266 | + | |
| 267 | +#define KVM_REG_FEATURE_LEVEL_MASK GENMASK(3, 0) | |
| 268 | + | |
| 269 | +/* | |
| 270 | + * Convert the workaround level into an easy-to-compare number, where higher | |
| 271 | + * values mean better protection. | |
| 272 | + */ | |
| 273 | +static int get_kernel_wa_level(u64 regid) | |
| 274 | +{ | |
| 275 | + switch (regid) { | |
| 276 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 277 | + switch (arm64_get_spectre_v2_state()) { | |
| 278 | + case SPECTRE_VULNERABLE: | |
| 279 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; | |
| 280 | + case SPECTRE_MITIGATED: | |
| 281 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; | |
| 282 | + case SPECTRE_UNAFFECTED: | |
| 283 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; | |
| 284 | + } | |
| 285 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; | |
| 286 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 287 | + switch (arm64_get_spectre_v4_state()) { | |
| 288 | + case SPECTRE_MITIGATED: | |
| 289 | + /* | |
| 290 | + * As for the hypercall discovery, we pretend we | |
| 291 | + * don't have any FW mitigation if SSBS is there at | |
| 292 | + * all times. | |
| 293 | + */ | |
| 294 | + if (cpus_have_final_cap(ARM64_SSBS)) | |
| 295 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; | |
| 296 | + fallthrough; | |
| 297 | + case SPECTRE_UNAFFECTED: | |
| 298 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; | |
| 299 | + case SPECTRE_VULNERABLE: | |
| 300 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; | |
| 301 | + } | |
| 302 | + break; | |
| 303 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: | |
| 304 | + switch (arm64_get_spectre_bhb_state()) { | |
| 305 | + case SPECTRE_VULNERABLE: | |
| 306 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; | |
| 307 | + case SPECTRE_MITIGATED: | |
| 308 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; | |
| 309 | + case SPECTRE_UNAFFECTED: | |
| 310 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; | |
| 311 | + } | |
| 312 | + return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; | |
| 313 | + } | |
| 314 | + | |
| 315 | + return -EINVAL; | |
| 316 | +} | |
| 317 | + | |
| 318 | +int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) | |
| 319 | +{ | |
| 320 | + struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; | |
| 321 | + void __user *uaddr = (void __user *)(long)reg->addr; | |
| 322 | + u64 val; | |
| 323 | + | |
| 324 | + switch (reg->id) { | |
| 325 | + case KVM_REG_ARM_PSCI_VERSION: | |
| 326 | + val = kvm_psci_version(vcpu); | |
| 327 | + break; | |
| 328 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 329 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 330 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: | |
| 331 | + val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; | |
| 332 | + break; | |
| 333 | + case KVM_REG_ARM_STD_BMAP: | |
| 334 | + val = READ_ONCE(smccc_feat->std_bmap); | |
| 335 | + break; | |
| 336 | + case KVM_REG_ARM_STD_HYP_BMAP: | |
| 337 | + val = READ_ONCE(smccc_feat->std_hyp_bmap); | |
| 338 | + break; | |
| 339 | + case KVM_REG_ARM_VENDOR_HYP_BMAP: | |
| 340 | + val = READ_ONCE(smccc_feat->vendor_hyp_bmap); | |
| 341 | + break; | |
| 342 | + default: | |
| 343 | + return -ENOENT; | |
| 344 | + } | |
| 345 | + | |
| 346 | + if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) | |
| 347 | + return -EFAULT; | |
| 348 | + | |
| 349 | + return 0; | |
| 350 | +} | |
| 351 | + | |
| 352 | +static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) | |
| 353 | +{ | |
| 354 | + int ret = 0; | |
| 355 | + struct kvm *kvm = vcpu->kvm; | |
| 356 | + struct kvm_smccc_features *smccc_feat = &kvm->arch.smccc_feat; | |
| 357 | + unsigned long *fw_reg_bmap, fw_reg_features; | |
| 358 | + | |
| 359 | + switch (reg_id) { | |
| 360 | + case KVM_REG_ARM_STD_BMAP: | |
| 361 | + fw_reg_bmap = &smccc_feat->std_bmap; | |
| 362 | + fw_reg_features = KVM_ARM_SMCCC_STD_FEATURES; | |
| 363 | + break; | |
| 364 | + case KVM_REG_ARM_STD_HYP_BMAP: | |
| 365 | + fw_reg_bmap = &smccc_feat->std_hyp_bmap; | |
| 366 | + fw_reg_features = KVM_ARM_SMCCC_STD_HYP_FEATURES; | |
| 367 | + break; | |
| 368 | + case KVM_REG_ARM_VENDOR_HYP_BMAP: | |
| 369 | + fw_reg_bmap = &smccc_feat->vendor_hyp_bmap; | |
| 370 | + fw_reg_features = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; | |
| 371 | + break; | |
| 372 | + default: | |
| 373 | + return -ENOENT; | |
| 374 | + } | |
| 375 | + | |
| 376 | + /* Check for unsupported bit */ | |
| 377 | + if (val & ~fw_reg_features) | |
| 378 | + return -EINVAL; | |
| 379 | + | |
| 380 | + mutex_lock(&kvm->lock); | |
| 381 | + | |
| 382 | + if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags) && | |
| 383 | + val != *fw_reg_bmap) { | |
| 384 | + ret = -EBUSY; | |
| 385 | + goto out; | |
| 386 | + } | |
| 387 | + | |
| 388 | + WRITE_ONCE(*fw_reg_bmap, val); | |
| 389 | +out: | |
| 390 | + mutex_unlock(&kvm->lock); | |
| 391 | + return ret; | |
| 392 | +} | |
| 393 | + | |
| 394 | +int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) | |
| 395 | +{ | |
| 396 | + void __user *uaddr = (void __user *)(long)reg->addr; | |
| 397 | + u64 val; | |
| 398 | + int wa_level; | |
| 399 | + | |
| 400 | + if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) | |
| 401 | + return -EFAULT; | |
| 402 | + | |
| 403 | + switch (reg->id) { | |
| 404 | + case KVM_REG_ARM_PSCI_VERSION: | |
| 405 | + { | |
| 406 | + bool wants_02; | |
| 407 | + | |
| 408 | + wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); | |
| 409 | + | |
| 410 | + switch (val) { | |
| 411 | + case KVM_ARM_PSCI_0_1: | |
| 412 | + if (wants_02) | |
| 413 | + return -EINVAL; | |
| 414 | + vcpu->kvm->arch.psci_version = val; | |
| 415 | + return 0; | |
| 416 | + case KVM_ARM_PSCI_0_2: | |
| 417 | + case KVM_ARM_PSCI_1_0: | |
| 418 | + case KVM_ARM_PSCI_1_1: | |
| 419 | + if (!wants_02) | |
| 420 | + return -EINVAL; | |
| 421 | + vcpu->kvm->arch.psci_version = val; | |
| 422 | + return 0; | |
| 423 | + } | |
| 424 | + break; | |
| 425 | + } | |
| 426 | + | |
| 427 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 428 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: | |
| 429 | + if (val & ~KVM_REG_FEATURE_LEVEL_MASK) | |
| 430 | + return -EINVAL; | |
| 431 | + | |
| 432 | + if (get_kernel_wa_level(reg->id) < val) | |
| 433 | + return -EINVAL; | |
| 434 | + | |
| 435 | + return 0; | |
| 436 | + | |
| 437 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 438 | + if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | | |
| 439 | + KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) | |
| 440 | + return -EINVAL; | |
| 441 | + | |
| 442 | + /* The enabled bit must not be set unless the level is AVAIL. */ | |
| 443 | + if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && | |
| 444 | + (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) | |
| 445 | + return -EINVAL; | |
| 446 | + | |
| 447 | + /* | |
| 448 | + * Map all the possible incoming states to the only two we | |
| 449 | + * really want to deal with. | |
| 450 | + */ | |
| 451 | + switch (val & KVM_REG_FEATURE_LEVEL_MASK) { | |
| 452 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: | |
| 453 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: | |
| 454 | + wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; | |
| 455 | + break; | |
| 456 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: | |
| 457 | + case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: | |
| 458 | + wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; | |
| 459 | + break; | |
| 460 | + default: | |
| 461 | + return -EINVAL; | |
| 462 | + } | |
| 463 | + | |
| 464 | + /* | |
| 465 | + * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the | |
| 466 | + * other way around. | |
| 467 | + */ | |
| 468 | + if (get_kernel_wa_level(reg->id) < wa_level) | |
| 469 | + return -EINVAL; | |
| 470 | + | |
| 471 | + return 0; | |
| 472 | + case KVM_REG_ARM_STD_BMAP: | |
| 473 | + case KVM_REG_ARM_STD_HYP_BMAP: | |
| 474 | + case KVM_REG_ARM_VENDOR_HYP_BMAP: | |
| 475 | + return kvm_arm_set_fw_reg_bmap(vcpu, reg->id, val); | |
| 476 | + default: | |
| 477 | + return -ENOENT; | |
| 478 | + } | |
| 479 | + | |
| 480 | + return -EINVAL; | |
| 481 | +} | |
| @@ -437,186 +437,3 @@ int kvm_psci_call(struct kvm_vcpu *vcpu) · 436 unmodified lines | ||
| 437 | 437 | return -EINVAL; |
| 438 | 438 | } |
| 439 | 439 | } |
| 440 | − | |
| 441 | −int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) | |
| 442 | −{ | |
| 443 | − return 4; /* PSCI version and three workaround registers */ | |
| 444 | −} | |
| 445 | − | |
| 446 | −int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) | |
| 447 | −{ | |
| 448 | − if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices++)) | |
| 449 | − return -EFAULT; | |
| 450 | − | |
| 451 | − if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, uindices++)) | |
| 452 | − return -EFAULT; | |
| 453 | − | |
| 454 | − if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++)) | |
| 455 | − return -EFAULT; | |
| 456 | − | |
| 457 | − if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++)) | |
| 458 | − return -EFAULT; | |
| 459 | − | |
| 460 | − return 0; | |
| 461 | −} | |
| 462 | − | |
| 463 | −#define KVM_REG_FEATURE_LEVEL_WIDTH 4 | |
| 464 | −#define KVM_REG_FEATURE_LEVEL_MASK (BIT(KVM_REG_FEATURE_LEVEL_WIDTH) - 1) | |
| 465 | − | |
| 466 | −/* | |
| 467 | − * Convert the workaround level into an easy-to-compare number, where higher | |
| 468 | − * values mean better protection. | |
| 469 | − */ | |
| 470 | −static int get_kernel_wa_level(u64 regid) | |
| 471 | −{ | |
| 472 | − switch (regid) { | |
| 473 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 474 | − switch (arm64_get_spectre_v2_state()) { | |
| 475 | − case SPECTRE_VULNERABLE: | |
| 476 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; | |
| 477 | − case SPECTRE_MITIGATED: | |
| 478 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; | |
| 479 | − case SPECTRE_UNAFFECTED: | |
| 480 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; | |
| 481 | − } | |
| 482 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; | |
| 483 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 484 | − switch (arm64_get_spectre_v4_state()) { | |
| 485 | − case SPECTRE_MITIGATED: | |
| 486 | − /* | |
| 487 | − * As for the hypercall discovery, we pretend we | |
| 488 | − * don't have any FW mitigation if SSBS is there at | |
| 489 | − * all times. | |
| 490 | − */ | |
| 491 | − if (cpus_have_final_cap(ARM64_SSBS)) | |
| 492 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; | |
| 493 | − fallthrough; | |
| 494 | − case SPECTRE_UNAFFECTED: | |
| 495 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; | |
| 496 | − case SPECTRE_VULNERABLE: | |
| 497 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; | |
| 498 | − } | |
| 499 | − break; | |
| 500 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: | |
| 501 | − switch (arm64_get_spectre_bhb_state()) { | |
| 502 | − case SPECTRE_VULNERABLE: | |
| 503 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; | |
| 504 | − case SPECTRE_MITIGATED: | |
| 505 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; | |
| 506 | − case SPECTRE_UNAFFECTED: | |
| 507 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; | |
| 508 | − } | |
| 509 | − return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; | |
| 510 | − } | |
| 511 | − | |
| 512 | − return -EINVAL; | |
| 513 | −} | |
| 514 | − | |
| 515 | −int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) | |
| 516 | −{ | |
| 517 | − void __user *uaddr = (void __user *)(long)reg->addr; | |
| 518 | − u64 val; | |
| 519 | − | |
| 520 | − switch (reg->id) { | |
| 521 | − case KVM_REG_ARM_PSCI_VERSION: | |
| 522 | − val = kvm_psci_version(vcpu); | |
| 523 | − break; | |
| 524 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 525 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 526 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: | |
| 527 | − val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; | |
| 528 | − break; | |
| 529 | − default: | |
| 530 | − return -ENOENT; | |
| 531 | − } | |
| 532 | − | |
| 533 | − if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) | |
| 534 | − return -EFAULT; | |
| 535 | − | |
| 536 | − return 0; | |
| 537 | −} | |
| 538 | − | |
| 539 | −int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) | |
| 540 | −{ | |
| 541 | − void __user *uaddr = (void __user *)(long)reg->addr; | |
| 542 | − u64 val; | |
| 543 | − int wa_level; | |
| 544 | − | |
| 545 | − if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) | |
| 546 | − return -EFAULT; | |
| 547 | − | |
| 548 | − switch (reg->id) { | |
| 549 | − case KVM_REG_ARM_PSCI_VERSION: | |
| 550 | − { | |
| 551 | − bool wants_02; | |
| 552 | − | |
| 553 | − wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); | |
| 554 | − | |
| 555 | − switch (val) { | |
| 556 | − case KVM_ARM_PSCI_0_1: | |
| 557 | − if (wants_02) | |
| 558 | − return -EINVAL; | |
| 559 | − vcpu->kvm->arch.psci_version = val; | |
| 560 | − return 0; | |
| 561 | − case KVM_ARM_PSCI_0_2: | |
| 562 | − case KVM_ARM_PSCI_1_0: | |
| 563 | − case KVM_ARM_PSCI_1_1: | |
| 564 | − if (!wants_02) | |
| 565 | − return -EINVAL; | |
| 566 | − vcpu->kvm->arch.psci_version = val; | |
| 567 | − return 0; | |
| 568 | − } | |
| 569 | − break; | |
| 570 | − } | |
| 571 | − | |
| 572 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: | |
| 573 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: | |
| 574 | − if (val & ~KVM_REG_FEATURE_LEVEL_MASK) | |
| 575 | − return -EINVAL; | |
| 576 | − | |
| 577 | − if (get_kernel_wa_level(reg->id) < val) | |
| 578 | − return -EINVAL; | |
| 579 | − | |
| 580 | − return 0; | |
| 581 | − | |
| 582 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: | |
| 583 | − if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | | |
| 584 | − KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) | |
| 585 | − return -EINVAL; | |
| 586 | − | |
| 587 | − /* The enabled bit must not be set unless the level is AVAIL. */ | |
| 588 | − if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && | |
| 589 | − (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) | |
| 590 | − return -EINVAL; | |
| 591 | − | |
| 592 | − /* | |
| 593 | − * Map all the possible incoming states to the only two we | |
| 594 | − * really want to deal with. | |
| 595 | − */ | |
| 596 | − switch (val & KVM_REG_FEATURE_LEVEL_MASK) { | |
| 597 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: | |
| 598 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: | |
| 599 | − wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; | |
| 600 | − break; | |
| 601 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: | |
| 602 | − case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: | |
| 603 | − wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; | |
| 604 | − break; | |
| 605 | − default: | |
| 606 | − return -EINVAL; | |
| 607 | − } | |
| 608 | − | |
| 609 | − /* | |
| 610 | − * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the | |
| 611 | − * other way around. | |
| 612 | − */ | |
| 613 | − if (get_kernel_wa_level(reg->id) < wa_level) | |
| 614 | − return -EINVAL; | |
| 615 | − | |
| 616 | − return 0; | |
| 617 | − default: | |
| 618 | − return -ENOENT; | |
| 619 | − } | |
| 620 | − | |
| 621 | − return -EINVAL; | |
| 622 | −} | |
| @@ -40,4 +40,12 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu, · 39 unmodified lines | ||
| 40 | 40 | vcpu_set_reg(vcpu, 3, a3); |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | +struct kvm_one_reg; | |
| 44 | + | |
| 45 | +void kvm_arm_init_hypercalls(struct kvm *kvm); | |
| 46 | +int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu); | |
| 47 | +int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); | |
| 48 | +int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); | |
| 49 | +int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); | |
| 50 | + | |
| 43 | 51 | #endif |
| @@ -39,11 +39,4 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu) · 38 unmodified lines | ||
| 39 | 39 | |
| 40 | 40 | int kvm_psci_call(struct kvm_vcpu *vcpu); |
| 41 | 41 | |
| 42 | −struct kvm_one_reg; | |
| 43 | − | |
| 44 | −int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu); | |
| 45 | −int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); | |
| 46 | −int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); | |
| 47 | −int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); | |
| 48 | − | |
| 49 | 42 | #endif /* __KVM_ARM_PSCI_H__ */ |
| @@ -0,0 +1,193 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (c) 2015, Linaro Limited | |
| 4 | + */ | |
| 5 | +#ifndef __LINUX_ARM_SMCCC_H | |
| 6 | +#define __LINUX_ARM_SMCCC_H | |
| 7 | + | |
| 8 | +#include <linux/const.h> | |
| 9 | + | |
| 10 | +/* | |
| 11 | + * This file provides common defines for ARM SMC Calling Convention as | |
| 12 | + * specified in | |
| 13 | + * https://developer.arm.com/docs/den0028/latest | |
| 14 | + * | |
| 15 | + * This code is up-to-date with version DEN 0028 C | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#define ARM_SMCCC_STD_CALL _AC(0,U) | |
| 19 | +#define ARM_SMCCC_FAST_CALL _AC(1,U) | |
| 20 | +#define ARM_SMCCC_TYPE_SHIFT 31 | |
| 21 | + | |
| 22 | +#define ARM_SMCCC_SMC_32 0 | |
| 23 | +#define ARM_SMCCC_SMC_64 1 | |
| 24 | +#define ARM_SMCCC_CALL_CONV_SHIFT 30 | |
| 25 | + | |
| 26 | +#define ARM_SMCCC_OWNER_MASK 0x3F | |
| 27 | +#define ARM_SMCCC_OWNER_SHIFT 24 | |
| 28 | + | |
| 29 | +#define ARM_SMCCC_FUNC_MASK 0xFFFF | |
| 30 | + | |
| 31 | +#define ARM_SMCCC_IS_FAST_CALL(smc_val) \ | |
| 32 | + ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT)) | |
| 33 | +#define ARM_SMCCC_IS_64(smc_val) \ | |
| 34 | + ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT)) | |
| 35 | +#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK) | |
| 36 | +#define ARM_SMCCC_OWNER_NUM(smc_val) \ | |
| 37 | + (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK) | |
| 38 | + | |
| 39 | +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ | |
| 40 | + (((type) << ARM_SMCCC_TYPE_SHIFT) | \ | |
| 41 | + ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \ | |
| 42 | + (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \ | |
| 43 | + ((func_num) & ARM_SMCCC_FUNC_MASK)) | |
| 44 | + | |
| 45 | +#define ARM_SMCCC_OWNER_ARCH 0 | |
| 46 | +#define ARM_SMCCC_OWNER_CPU 1 | |
| 47 | +#define ARM_SMCCC_OWNER_SIP 2 | |
| 48 | +#define ARM_SMCCC_OWNER_OEM 3 | |
| 49 | +#define ARM_SMCCC_OWNER_STANDARD 4 | |
| 50 | +#define ARM_SMCCC_OWNER_STANDARD_HYP 5 | |
| 51 | +#define ARM_SMCCC_OWNER_VENDOR_HYP 6 | |
| 52 | +#define ARM_SMCCC_OWNER_TRUSTED_APP 48 | |
| 53 | +#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 | |
| 54 | +#define ARM_SMCCC_OWNER_TRUSTED_OS 50 | |
| 55 | +#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63 | |
| 56 | + | |
| 57 | +#define ARM_SMCCC_FUNC_QUERY_CALL_UID 0xff01 | |
| 58 | + | |
| 59 | +#define ARM_SMCCC_QUIRK_NONE 0 | |
| 60 | +#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */ | |
| 61 | + | |
| 62 | +#define ARM_SMCCC_VERSION_1_0 0x10000 | |
| 63 | +#define ARM_SMCCC_VERSION_1_1 0x10001 | |
| 64 | +#define ARM_SMCCC_VERSION_1_2 0x10002 | |
| 65 | +#define ARM_SMCCC_VERSION_1_3 0x10003 | |
| 66 | + | |
| 67 | +#define ARM_SMCCC_1_3_SVE_HINT 0x10000 | |
| 68 | + | |
| 69 | +#define ARM_SMCCC_VERSION_FUNC_ID \ | |
| 70 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 71 | + ARM_SMCCC_SMC_32, \ | |
| 72 | + 0, 0) | |
| 73 | + | |
| 74 | +#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID \ | |
| 75 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 76 | + ARM_SMCCC_SMC_32, \ | |
| 77 | + 0, 1) | |
| 78 | + | |
| 79 | +#define ARM_SMCCC_ARCH_SOC_ID \ | |
| 80 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 81 | + ARM_SMCCC_SMC_32, \ | |
| 82 | + 0, 2) | |
| 83 | + | |
| 84 | +#define ARM_SMCCC_ARCH_WORKAROUND_1 \ | |
| 85 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 86 | + ARM_SMCCC_SMC_32, \ | |
| 87 | + 0, 0x8000) | |
| 88 | + | |
| 89 | +#define ARM_SMCCC_ARCH_WORKAROUND_2 \ | |
| 90 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 91 | + ARM_SMCCC_SMC_32, \ | |
| 92 | + 0, 0x7fff) | |
| 93 | + | |
| 94 | +#define ARM_SMCCC_ARCH_WORKAROUND_3 \ | |
| 95 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 96 | + ARM_SMCCC_SMC_32, \ | |
| 97 | + 0, 0x3fff) | |
| 98 | + | |
| 99 | +#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \ | |
| 100 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 101 | + ARM_SMCCC_SMC_32, \ | |
| 102 | + ARM_SMCCC_OWNER_VENDOR_HYP, \ | |
| 103 | + ARM_SMCCC_FUNC_QUERY_CALL_UID) | |
| 104 | + | |
| 105 | +/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */ | |
| 106 | +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 0xb66fb428U | |
| 107 | +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 0xe911c52eU | |
| 108 | +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 0x564bcaa9U | |
| 109 | +#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3 0x743a004dU | |
| 110 | + | |
| 111 | +/* KVM "vendor specific" services */ | |
| 112 | +#define ARM_SMCCC_KVM_FUNC_FEATURES 0 | |
| 113 | +#define ARM_SMCCC_KVM_FUNC_PTP 1 | |
| 114 | +#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127 | |
| 115 | +#define ARM_SMCCC_KVM_NUM_FUNCS 128 | |
| 116 | + | |
| 117 | +#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID \ | |
| 118 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 119 | + ARM_SMCCC_SMC_32, \ | |
| 120 | + ARM_SMCCC_OWNER_VENDOR_HYP, \ | |
| 121 | + ARM_SMCCC_KVM_FUNC_FEATURES) | |
| 122 | + | |
| 123 | +#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1 | |
| 124 | + | |
| 125 | +/* | |
| 126 | + * ptp_kvm is a feature used for time sync between vm and host. | |
| 127 | + * ptp_kvm module in guest kernel will get service from host using | |
| 128 | + * this hypercall ID. | |
| 129 | + */ | |
| 130 | +#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \ | |
| 131 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 132 | + ARM_SMCCC_SMC_32, \ | |
| 133 | + ARM_SMCCC_OWNER_VENDOR_HYP, \ | |
| 134 | + ARM_SMCCC_KVM_FUNC_PTP) | |
| 135 | + | |
| 136 | +/* ptp_kvm counter type ID */ | |
| 137 | +#define KVM_PTP_VIRT_COUNTER 0 | |
| 138 | +#define KVM_PTP_PHYS_COUNTER 1 | |
| 139 | + | |
| 140 | +/* Paravirtualised time calls (defined by ARM DEN0057A) */ | |
| 141 | +#define ARM_SMCCC_HV_PV_TIME_FEATURES \ | |
| 142 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 143 | + ARM_SMCCC_SMC_64, \ | |
| 144 | + ARM_SMCCC_OWNER_STANDARD_HYP, \ | |
| 145 | + 0x20) | |
| 146 | + | |
| 147 | +#define ARM_SMCCC_HV_PV_TIME_ST \ | |
| 148 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 149 | + ARM_SMCCC_SMC_64, \ | |
| 150 | + ARM_SMCCC_OWNER_STANDARD_HYP, \ | |
| 151 | + 0x21) | |
| 152 | + | |
| 153 | +/* TRNG entropy source calls (defined by ARM DEN0098) */ | |
| 154 | +#define ARM_SMCCC_TRNG_VERSION \ | |
| 155 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 156 | + ARM_SMCCC_SMC_32, \ | |
| 157 | + ARM_SMCCC_OWNER_STANDARD, \ | |
| 158 | + 0x50) | |
| 159 | + | |
| 160 | +#define ARM_SMCCC_TRNG_FEATURES \ | |
| 161 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 162 | + ARM_SMCCC_SMC_32, \ | |
| 163 | + ARM_SMCCC_OWNER_STANDARD, \ | |
| 164 | + 0x51) | |
| 165 | + | |
| 166 | +#define ARM_SMCCC_TRNG_GET_UUID \ | |
| 167 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 168 | + ARM_SMCCC_SMC_32, \ | |
| 169 | + ARM_SMCCC_OWNER_STANDARD, \ | |
| 170 | + 0x52) | |
| 171 | + | |
| 172 | +#define ARM_SMCCC_TRNG_RND32 \ | |
| 173 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 174 | + ARM_SMCCC_SMC_32, \ | |
| 175 | + ARM_SMCCC_OWNER_STANDARD, \ | |
| 176 | + 0x53) | |
| 177 | + | |
| 178 | +#define ARM_SMCCC_TRNG_RND64 \ | |
| 179 | + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ | |
| 180 | + ARM_SMCCC_SMC_64, \ | |
| 181 | + ARM_SMCCC_OWNER_STANDARD, \ | |
| 182 | + 0x53) | |
| 183 | + | |
| 184 | +/* | |
| 185 | + * Return codes defined in ARM DEN 0070A | |
| 186 | + * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C | |
| 187 | + */ | |
| 188 | +#define SMCCC_RET_SUCCESS 0 | |
| 189 | +#define SMCCC_RET_NOT_SUPPORTED -1 | |
| 190 | +#define SMCCC_RET_NOT_REQUIRED -2 | |
| 191 | +#define SMCCC_RET_INVALID_PARAMETER -3 | |
| 192 | + | |
| 193 | +#endif /*__LINUX_ARM_SMCCC_H*/ | |
| @@ -2,7 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | /aarch64/arch_timer |
| 3 | 3 | /aarch64/debug-exceptions |
| 4 | 4 | /aarch64/get-reg-list |
| 5 | −/aarch64/psci_cpu_on_test | |
| 5 | +/aarch64/hypercalls | |
| 6 | +/aarch64/psci_test | |
| 6 | 7 | /aarch64/vcpu_width_config |
| 7 | 8 | /aarch64/vgic_init |
| 8 | 9 | /aarch64/vgic_irq |
| @@ -105,7 +105,8 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test · 104 unmodified lines | ||
| 105 | 105 | TEST_GEN_PROGS_aarch64 += aarch64/arch_timer |
| 106 | 106 | TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions |
| 107 | 107 | TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list |
| 108 | −TEST_GEN_PROGS_aarch64 += aarch64/psci_cpu_on_test | |
| 108 | +TEST_GEN_PROGS_aarch64 += aarch64/hypercalls | |
| 109 | +TEST_GEN_PROGS_aarch64 += aarch64/psci_test | |
| 109 | 110 | TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config |
| 110 | 111 | TEST_GEN_PROGS_aarch64 += aarch64/vgic_init |
| 111 | 112 | TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq |
| @@ -294,6 +294,11 @@ static void print_reg(struct vcpu_config *c, __u64 id) · 293 unmodified lines | ||
| 294 | 294 | "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id); |
| 295 | 295 | printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff); |
| 296 | 296 | break; |
| 297 | + case KVM_REG_ARM_FW_FEAT_BMAP: | |
| 298 | + TEST_ASSERT(id == KVM_REG_ARM_FW_FEAT_BMAP_REG(id & 0xffff), | |
| 299 | + "%s: Unexpected bits set in the bitmap feature FW reg id: 0x%llx", config_name(c), id); | |
| 300 | + printf("\tKVM_REG_ARM_FW_FEAT_BMAP_REG(%lld),\n", id & 0xffff); | |
| 301 | + break; | |
| 297 | 302 | case KVM_REG_ARM64_SVE: |
| 298 | 303 | if (has_cap(c, KVM_CAP_ARM_SVE)) |
| 299 | 304 | printf("\t%s,\n", sve_id_to_str(c, id)); |
| @@ -692,6 +697,9 @@ static __u64 base_regs[] = { · 392 unmodified lines | ||
| 692 | 697 | KVM_REG_ARM_FW_REG(1), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 */ |
| 693 | 698 | KVM_REG_ARM_FW_REG(2), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 */ |
| 694 | 699 | KVM_REG_ARM_FW_REG(3), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 */ |
| 700 | + KVM_REG_ARM_FW_FEAT_BMAP_REG(0), /* KVM_REG_ARM_STD_BMAP */ | |
| 701 | + KVM_REG_ARM_FW_FEAT_BMAP_REG(1), /* KVM_REG_ARM_STD_HYP_BMAP */ | |
| 702 | + KVM_REG_ARM_FW_FEAT_BMAP_REG(2), /* KVM_REG_ARM_VENDOR_HYP_BMAP */ | |
| 695 | 703 | ARM64_SYS_REG(3, 3, 14, 3, 1), /* CNTV_CTL_EL0 */ |
| 696 | 704 | ARM64_SYS_REG(3, 3, 14, 3, 2), /* CNTV_CVAL_EL0 */ |
| 697 | 705 | ARM64_SYS_REG(3, 3, 14, 0, 2), |
| @@ -0,0 +1,336 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | + | |
| 3 | +/* hypercalls: Check the ARM64's psuedo-firmware bitmap register interface. | |
| 4 | + * | |
| 5 | + * The test validates the basic hypercall functionalities that are exposed | |
| 6 | + * via the psuedo-firmware bitmap register. This includes the registers' | |
| 7 | + * read/write behavior before and after the VM has started, and if the | |
| 8 | + * hypercalls are properly masked or unmasked to the guest when disabled or | |
| 9 | + * enabled from the KVM userspace, respectively. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <errno.h> | |
| 13 | +#include <linux/arm-smccc.h> | |
| 14 | +#include <asm/kvm.h> | |
| 15 | +#include <kvm_util.h> | |
| 16 | + | |
| 17 | +#include "processor.h" | |
| 18 | + | |
| 19 | +#define FW_REG_ULIMIT_VAL(max_feat_bit) (GENMASK(max_feat_bit, 0)) | |
| 20 | + | |
| 21 | +/* Last valid bits of the bitmapped firmware registers */ | |
| 22 | +#define KVM_REG_ARM_STD_BMAP_BIT_MAX 0 | |
| 23 | +#define KVM_REG_ARM_STD_HYP_BMAP_BIT_MAX 0 | |
| 24 | +#define KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_MAX 1 | |
| 25 | + | |
| 26 | +struct kvm_fw_reg_info { | |
| 27 | + uint64_t reg; /* Register definition */ | |
| 28 | + uint64_t max_feat_bit; /* Bit that represents the upper limit of the feature-map */ | |
| 29 | +}; | |
| 30 | + | |
| 31 | +#define FW_REG_INFO(r) \ | |
| 32 | + { \ | |
| 33 | + .reg = r, \ | |
| 34 | + .max_feat_bit = r##_BIT_MAX, \ | |
| 35 | + } | |
| 36 | + | |
| 37 | +static const struct kvm_fw_reg_info fw_reg_info[] = { | |
| 38 | + FW_REG_INFO(KVM_REG_ARM_STD_BMAP), | |
| 39 | + FW_REG_INFO(KVM_REG_ARM_STD_HYP_BMAP), | |
| 40 | + FW_REG_INFO(KVM_REG_ARM_VENDOR_HYP_BMAP), | |
| 41 | +}; | |
| 42 | + | |
| 43 | +enum test_stage { | |
| 44 | + TEST_STAGE_REG_IFACE, | |
| 45 | + TEST_STAGE_HVC_IFACE_FEAT_DISABLED, | |
| 46 | + TEST_STAGE_HVC_IFACE_FEAT_ENABLED, | |
| 47 | + TEST_STAGE_HVC_IFACE_FALSE_INFO, | |
| 48 | + TEST_STAGE_END, | |
| 49 | +}; | |
| 50 | + | |
| 51 | +static int stage = TEST_STAGE_REG_IFACE; | |
| 52 | + | |
| 53 | +struct test_hvc_info { | |
| 54 | + uint32_t func_id; | |
| 55 | + uint64_t arg1; | |
| 56 | +}; | |
| 57 | + | |
| 58 | +#define TEST_HVC_INFO(f, a1) \ | |
| 59 | + { \ | |
| 60 | + .func_id = f, \ | |
| 61 | + .arg1 = a1, \ | |
| 62 | + } | |
| 63 | + | |
| 64 | +static const struct test_hvc_info hvc_info[] = { | |
| 65 | + /* KVM_REG_ARM_STD_BMAP */ | |
| 66 | + TEST_HVC_INFO(ARM_SMCCC_TRNG_VERSION, 0), | |
| 67 | + TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_TRNG_RND64), | |
| 68 | + TEST_HVC_INFO(ARM_SMCCC_TRNG_GET_UUID, 0), | |
| 69 | + TEST_HVC_INFO(ARM_SMCCC_TRNG_RND32, 0), | |
| 70 | + TEST_HVC_INFO(ARM_SMCCC_TRNG_RND64, 0), | |
| 71 | + | |
| 72 | + /* KVM_REG_ARM_STD_HYP_BMAP */ | |
| 73 | + TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_HV_PV_TIME_FEATURES), | |
| 74 | + TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_HV_PV_TIME_ST), | |
| 75 | + TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_ST, 0), | |
| 76 | + | |
| 77 | + /* KVM_REG_ARM_VENDOR_HYP_BMAP */ | |
| 78 | + TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID, | |
| 79 | + ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID), | |
| 80 | + TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0), | |
| 81 | + TEST_HVC_INFO(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, KVM_PTP_VIRT_COUNTER), | |
| 82 | +}; | |
| 83 | + | |
| 84 | +/* Feed false hypercall info to test the KVM behavior */ | |
| 85 | +static const struct test_hvc_info false_hvc_info[] = { | |
| 86 | + /* Feature support check against a different family of hypercalls */ | |
| 87 | + TEST_HVC_INFO(ARM_SMCCC_TRNG_FEATURES, ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID), | |
| 88 | + TEST_HVC_INFO(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_TRNG_RND64), | |
| 89 | + TEST_HVC_INFO(ARM_SMCCC_HV_PV_TIME_FEATURES, ARM_SMCCC_TRNG_RND64), | |
| 90 | +}; | |
| 91 | + | |
| 92 | +static void guest_test_hvc(const struct test_hvc_info *hc_info) | |
| 93 | +{ | |
| 94 | + unsigned int i; | |
| 95 | + struct arm_smccc_res res; | |
| 96 | + unsigned int hvc_info_arr_sz; | |
| 97 | + | |
| 98 | + hvc_info_arr_sz = | |
| 99 | + hc_info == hvc_info ? ARRAY_SIZE(hvc_info) : ARRAY_SIZE(false_hvc_info); | |
| 100 | + | |
| 101 | + for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) { | |
| 102 | + memset(&res, 0, sizeof(res)); | |
| 103 | + smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res); | |
| 104 | + | |
| 105 | + switch (stage) { | |
| 106 | + case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: | |
| 107 | + case TEST_STAGE_HVC_IFACE_FALSE_INFO: | |
| 108 | + GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED, | |
| 109 | + res.a0, hc_info->func_id, hc_info->arg1); | |
| 110 | + break; | |
| 111 | + case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: | |
| 112 | + GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED, | |
| 113 | + res.a0, hc_info->func_id, hc_info->arg1); | |
| 114 | + break; | |
| 115 | + default: | |
| 116 | + GUEST_ASSERT_1(0, stage); | |
| 117 | + } | |
| 118 | + } | |
| 119 | +} | |
| 120 | + | |
| 121 | +static void guest_code(void) | |
| 122 | +{ | |
| 123 | + while (stage != TEST_STAGE_END) { | |
| 124 | + switch (stage) { | |
| 125 | + case TEST_STAGE_REG_IFACE: | |
| 126 | + break; | |
| 127 | + case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: | |
| 128 | + case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: | |
| 129 | + guest_test_hvc(hvc_info); | |
| 130 | + break; | |
| 131 | + case TEST_STAGE_HVC_IFACE_FALSE_INFO: | |
| 132 | + guest_test_hvc(false_hvc_info); | |
| 133 | + break; | |
| 134 | + default: | |
| 135 | + GUEST_ASSERT_1(0, stage); | |
| 136 | + } | |
| 137 | + | |
| 138 | + GUEST_SYNC(stage); | |
| 139 | + } | |
| 140 | + | |
| 141 | + GUEST_DONE(); | |
| 142 | +} | |
| 143 | + | |
| 144 | +static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val) | |
| 145 | +{ | |
| 146 | + struct kvm_one_reg reg = { | |
| 147 | + .id = id, | |
| 148 | + .addr = (uint64_t)&val, | |
| 149 | + }; | |
| 150 | + | |
| 151 | + return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); | |
| 152 | +} | |
| 153 | + | |
| 154 | +static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr) | |
| 155 | +{ | |
| 156 | + struct kvm_one_reg reg = { | |
| 157 | + .id = id, | |
| 158 | + .addr = (uint64_t)addr, | |
| 159 | + }; | |
| 160 | + | |
| 161 | + vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, ®); | |
| 162 | +} | |
| 163 | + | |
| 164 | +struct st_time { | |
| 165 | + uint32_t rev; | |
| 166 | + uint32_t attr; | |
| 167 | + uint64_t st_time; | |
| 168 | +}; | |
| 169 | + | |
| 170 | +#define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) | |
| 171 | +#define ST_GPA_BASE (1 << 30) | |
| 172 | + | |
| 173 | +static void steal_time_init(struct kvm_vm *vm) | |
| 174 | +{ | |
| 175 | + uint64_t st_ipa = (ulong)ST_GPA_BASE; | |
| 176 | + unsigned int gpages; | |
| 177 | + struct kvm_device_attr dev = { | |
| 178 | + .group = KVM_ARM_VCPU_PVTIME_CTRL, | |
| 179 | + .attr = KVM_ARM_VCPU_PVTIME_IPA, | |
| 180 | + .addr = (uint64_t)&st_ipa, | |
| 181 | + }; | |
| 182 | + | |
| 183 | + gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE); | |
| 184 | + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); | |
| 185 | + | |
| 186 | + vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev); | |
| 187 | +} | |
| 188 | + | |
| 189 | +static void test_fw_regs_before_vm_start(struct kvm_vm *vm) | |
| 190 | +{ | |
| 191 | + uint64_t val; | |
| 192 | + unsigned int i; | |
| 193 | + int ret; | |
| 194 | + | |
| 195 | + for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) { | |
| 196 | + const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; | |
| 197 | + | |
| 198 | + /* First 'read' should be an upper limit of the features supported */ | |
| 199 | + get_fw_reg(vm, reg_info->reg, &val); | |
| 200 | + TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), | |
| 201 | + "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n", | |
| 202 | + reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val); | |
| 203 | + | |
| 204 | + /* Test a 'write' by disabling all the features of the register map */ | |
| 205 | + ret = set_fw_reg(vm, reg_info->reg, 0); | |
| 206 | + TEST_ASSERT(ret == 0, | |
| 207 | + "Failed to clear all the features of reg: 0x%lx; ret: %d\n", | |
| 208 | + reg_info->reg, errno); | |
| 209 | + | |
| 210 | + get_fw_reg(vm, reg_info->reg, &val); | |
| 211 | + TEST_ASSERT(val == 0, | |
| 212 | + "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); | |
| 213 | + | |
| 214 | + /* | |
| 215 | + * Test enabling a feature that's not supported. | |
| 216 | + * Avoid this check if all the bits are occupied. | |
| 217 | + */ | |
| 218 | + if (reg_info->max_feat_bit < 63) { | |
| 219 | + ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); | |
| 220 | + TEST_ASSERT(ret != 0 && errno == EINVAL, | |
| 221 | + "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n", | |
| 222 | + errno, reg_info->reg); | |
| 223 | + } | |
| 224 | + } | |
| 225 | +} | |
| 226 | + | |
| 227 | +static void test_fw_regs_after_vm_start(struct kvm_vm *vm) | |
| 228 | +{ | |
| 229 | + uint64_t val; | |
| 230 | + unsigned int i; | |
| 231 | + int ret; | |
| 232 | + | |
| 233 | + for (i = 0; i < ARRAY_SIZE(fw_reg_info); i++) { | |
| 234 | + const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; | |
| 235 | + | |
| 236 | + /* | |
| 237 | + * Before starting the VM, the test clears all the bits. | |
| 238 | + * Check if that's still the case. | |
| 239 | + */ | |
| 240 | + get_fw_reg(vm, reg_info->reg, &val); | |
| 241 | + TEST_ASSERT(val == 0, | |
| 242 | + "Expected all the features to be cleared for reg: 0x%lx\n", | |
| 243 | + reg_info->reg); | |
| 244 | + | |
| 245 | + /* | |
| 246 | + * Since the VM has run at least once, KVM shouldn't allow modification of | |
| 247 | + * the registers and should return EBUSY. Set the registers and check for | |
| 248 | + * the expected errno. | |
| 249 | + */ | |
| 250 | + ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); | |
| 251 | + TEST_ASSERT(ret != 0 && errno == EBUSY, | |
| 252 | + "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n", | |
| 253 | + errno, reg_info->reg); | |
| 254 | + } | |
| 255 | +} | |
| 256 | + | |
| 257 | +static struct kvm_vm *test_vm_create(void) | |
| 258 | +{ | |
| 259 | + struct kvm_vm *vm; | |
| 260 | + | |
| 261 | + vm = vm_create_default(0, 0, guest_code); | |
| 262 | + | |
| 263 | + ucall_init(vm, NULL); | |
| 264 | + steal_time_init(vm); | |
| 265 | + | |
| 266 | + return vm; | |
| 267 | +} | |
| 268 | + | |
| 269 | +static struct kvm_vm *test_guest_stage(struct kvm_vm *vm) | |
| 270 | +{ | |
| 271 | + struct kvm_vm *ret_vm = vm; | |
| 272 | + | |
| 273 | + pr_debug("Stage: %d\n", stage); | |
| 274 | + | |
| 275 | + switch (stage) { | |
| 276 | + case TEST_STAGE_REG_IFACE: | |
| 277 | + test_fw_regs_after_vm_start(vm); | |
| 278 | + break; | |
| 279 | + case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: | |
| 280 | + /* Start a new VM so that all the features are now enabled by default */ | |
| 281 | + kvm_vm_free(vm); | |
| 282 | + ret_vm = test_vm_create(); | |
| 283 | + break; | |
| 284 | + case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: | |
| 285 | + case TEST_STAGE_HVC_IFACE_FALSE_INFO: | |
| 286 | + break; | |
| 287 | + default: | |
| 288 | + TEST_FAIL("Unknown test stage: %d\n", stage); | |
| 289 | + } | |
| 290 | + | |
| 291 | + stage++; | |
| 292 | + sync_global_to_guest(vm, stage); | |
| 293 | + | |
| 294 | + return ret_vm; | |
| 295 | +} | |
| 296 | + | |
| 297 | +static void test_run(void) | |
| 298 | +{ | |
| 299 | + struct kvm_vm *vm; | |
| 300 | + struct ucall uc; | |
| 301 | + bool guest_done = false; | |
| 302 | + | |
| 303 | + vm = test_vm_create(); | |
| 304 | + | |
| 305 | + test_fw_regs_before_vm_start(vm); | |
| 306 | + | |
| 307 | + while (!guest_done) { | |
| 308 | + vcpu_run(vm, 0); | |
| 309 | + | |
| 310 | + switch (get_ucall(vm, 0, &uc)) { | |
| 311 | + case UCALL_SYNC: | |
| 312 | + vm = test_guest_stage(vm); | |
| 313 | + break; | |
| 314 | + case UCALL_DONE: | |
| 315 | + guest_done = true; | |
| 316 | + break; | |
| 317 | + case UCALL_ABORT: | |
| 318 | + TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u", | |
| 319 | + (const char *)uc.args[0], __FILE__, uc.args[1], | |
| 320 | + uc.args[2], uc.args[3], uc.args[4], stage); | |
| 321 | + break; | |
| 322 | + default: | |
| 323 | + TEST_FAIL("Unexpected guest exit\n"); | |
| 324 | + } | |
| 325 | + } | |
| 326 | + | |
| 327 | + kvm_vm_free(vm); | |
| 328 | +} | |
| 329 | + | |
| 330 | +int main(void) | |
| 331 | +{ | |
| 332 | + setbuf(stdout, NULL); | |
| 333 | + | |
| 334 | + test_run(); | |
| 335 | + return 0; | |
| 336 | +} | |
| @@ -26,32 +26,23 @@ · 25 unmodified lines | ||
| 26 | 26 | static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr, |
| 27 | 27 | uint64_t context_id) |
| 28 | 28 | { |
| 29 | − register uint64_t x0 asm("x0") = PSCI_0_2_FN64_CPU_ON; | |
| 30 | − register uint64_t x1 asm("x1") = target_cpu; | |
| 31 | − register uint64_t x2 asm("x2") = entry_addr; | |
| 32 | − register uint64_t x3 asm("x3") = context_id; | |
| 29 | + struct arm_smccc_res res; | |
| 33 | 30 | |
| 34 | − asm("hvc #0" | |
| 35 | − : "=r"(x0) | |
| 36 | − : "r"(x0), "r"(x1), "r"(x2), "r"(x3) | |
| 37 | − : "memory"); | |
| 31 | + smccc_hvc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id, | |
| 32 | + 0, 0, 0, 0, &res); | |
| 38 | 33 | |
| 39 | − return x0; | |
| 34 | + return res.a0; | |
| 40 | 35 | } |
| 41 | 36 | |
| 42 | 37 | static uint64_t psci_affinity_info(uint64_t target_affinity, |
| 43 | 38 | uint64_t lowest_affinity_level) |
| 44 | 39 | { |
| 45 | − register uint64_t x0 asm("x0") = PSCI_0_2_FN64_AFFINITY_INFO; | |
| 46 | − register uint64_t x1 asm("x1") = target_affinity; | |
| 47 | − register uint64_t x2 asm("x2") = lowest_affinity_level; | |
| 40 | + struct arm_smccc_res res; | |
| 48 | 41 | |
| 49 | − asm("hvc #0" | |
| 50 | − : "=r"(x0) | |
| 51 | − : "r"(x0), "r"(x1), "r"(x2) | |
| 52 | − : "memory"); | |
| 42 | + smccc_hvc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level, | |
| 43 | + 0, 0, 0, 0, 0, &res); | |
| 53 | 44 | |
| 54 | − return x0; | |
| 45 | + return res.a0; | |
| 55 | 46 | } |
| 56 | 47 | |
| 57 | 48 | static void guest_main(uint64_t target_cpu) |
| @@ -185,4 +185,26 @@ static inline void local_irq_disable(void) · 184 unmodified lines | ||
| 185 | 185 | asm volatile("msr daifset, #3" : : : "memory"); |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | +/** | |
| 189 | + * struct arm_smccc_res - Result from SMC/HVC call | |
| 190 | + * @a0-a3 result values from registers 0 to 3 | |
| 191 | + */ | |
| 192 | +struct arm_smccc_res { | |
| 193 | + unsigned long a0; | |
| 194 | + unsigned long a1; | |
| 195 | + unsigned long a2; | |
| 196 | + unsigned long a3; | |
| 197 | +}; | |
| 198 | + | |
| 199 | +/** | |
| 200 | + * smccc_hvc - Invoke a SMCCC function using the hvc conduit | |
| 201 | + * @function_id: the SMCCC function to be called | |
| 202 | + * @arg0-arg6: SMCCC function arguments, corresponding to registers x1-x7 | |
| 203 | + * @res: pointer to write the return values from registers x0-x3 | |
| 204 | + * | |
| 205 | + */ | |
| 206 | +void smccc_hvc(uint32_t function_id, uint64_t arg0, uint64_t arg1, | |
| 207 | + uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, | |
| 208 | + uint64_t arg6, struct arm_smccc_res *res); | |
| 209 | + | |
| 188 | 210 | #endif /* SELFTEST_KVM_PROCESSOR_H */ |
| @@ -500,3 +500,28 @@ void __attribute__((constructor)) init_guest_modes(void) · 499 unmodified lines | ||
| 500 | 500 | { |
| 501 | 501 | guest_modes_append_default(); |
| 502 | 502 | } |
| 503 | + | |
| 504 | +void smccc_hvc(uint32_t function_id, uint64_t arg0, uint64_t arg1, | |
| 505 | + uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, | |
| 506 | + uint64_t arg6, struct arm_smccc_res *res) | |
| 507 | +{ | |
| 508 | + asm volatile("mov w0, %w[function_id]\n" | |
| 509 | + "mov x1, %[arg0]\n" | |
| 510 | + "mov x2, %[arg1]\n" | |
| 511 | + "mov x3, %[arg2]\n" | |
| 512 | + "mov x4, %[arg3]\n" | |
| 513 | + "mov x5, %[arg4]\n" | |
| 514 | + "mov x6, %[arg5]\n" | |
| 515 | + "mov x7, %[arg6]\n" | |
| 516 | + "hvc #0\n" | |
| 517 | + "mov %[res0], x0\n" | |
| 518 | + "mov %[res1], x1\n" | |
| 519 | + "mov %[res2], x2\n" | |
| 520 | + "mov %[res3], x3\n" | |
| 521 | + : [res0] "=r"(res->a0), [res1] "=r"(res->a1), | |
| 522 | + [res2] "=r"(res->a2), [res3] "=r"(res->a3) | |
| 523 | + : [function_id] "r"(function_id), [arg0] "r"(arg0), | |
| 524 | + [arg1] "r"(arg1), [arg2] "r"(arg2), [arg3] "r"(arg3), | |
| 525 | + [arg4] "r"(arg4), [arg5] "r"(arg5), [arg6] "r"(arg6) | |
| 526 | + : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"); | |
| 527 | +} | |
| @@ -118,17 +118,10 @@ struct st_time { · 117 unmodified lines | ||
| 118 | 118 | |
| 119 | 119 | static int64_t smccc(uint32_t func, uint64_t arg) |
| 120 | 120 | { |
| 121 | − unsigned long ret; | |
| 121 | + struct arm_smccc_res res; | |
| 122 | 122 | |
| 123 | − asm volatile( | |
| 124 | − "mov w0, %w1\n" | |
| 125 | − "mov x1, %2\n" | |
| 126 | − "hvc #0\n" | |
| 127 | − "mov %0, x0\n" | |
| 128 | − : "=r" (ret) : "r" (func), "r" (arg) : | |
| 129 | − "x0", "x1", "x2", "x3"); | |
| 130 | − | |
| 131 | − return ret; | |
| 123 | + smccc_hvc(func, arg, 0, 0, 0, 0, 0, 0, &res); | |
| 124 | + return res.a0; | |
| 132 | 125 | } |
| 133 | 126 | |
| 134 | 127 | static void check_status(struct st_time *st) |