* 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 | After the vcpu's SVE configuration is finalized, further attempts to | 2601 | After the vcpu's SVE configuration is finalized, further attempts to |
| 2602 | write this register will fail with EPERM. | 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 | MIPS registers are mapped using the lower 32 bits. The upper 16 of that is | 2623 | MIPS registers are mapped using the lower 32 bits. The upper 16 of that is |
| 2606 | the register group type: | 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 | :maxdepth: 2 | 8 | :maxdepth: 2 |
| 9 | 9 | ||
| 10 | hyp-abi | 10 | hyp-abi |
| 11 | psci | 11 | hypercalls |
| 12 | pvtime | 12 | pvtime |
| 13 | ptp_kvm | 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 | struct kvm_arch_memory_slot { | 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 | struct kvm_arch { | 117 | struct kvm_arch { |
| 105 | struct kvm_s2_mmu mmu; | 118 | struct kvm_s2_mmu mmu; |
| 106 | 119 | ||
| @@ -150,6 +163,9 @@ struct kvm_arch { · 43 unmodified lines | |||
| 150 | 163 | ||
| 151 | u8 pfr0_csv2; | 164 | u8 pfr0_csv2; |
| 152 | u8 pfr0_csv3; | 165 | u8 pfr0_csv3; |
| 166 | |||
| 167 | /* Hypercall features firmware registers' descriptor */ | ||
| 168 | struct kvm_smccc_features smccc_feat; | ||
| 153 | }; | 169 | }; |
| 154 | 170 | ||
| 155 | struct kvm_vcpu_fault_info { | 171 | struct kvm_vcpu_fault_info { |
| @@ -332,6 +332,40 @@ struct kvm_arm_copy_mte_tags { · 331 unmodified lines | |||
| 332 | #define KVM_ARM64_SVE_VLS_WORDS \ | 332 | #define KVM_ARM64_SVE_VLS_WORDS \ |
| 333 | ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1) | 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 | /* Device Control API: ARM VGIC */ | 369 | /* Device Control API: ARM VGIC */ |
| 336 | #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 | 370 | #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 |
| 337 | #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 | 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 | kvm->arch.max_vcpus = kvm_arm_default_max_vcpus(); | 156 | kvm->arch.max_vcpus = kvm_arm_default_max_vcpus(); |
| 157 | 157 | ||
| 158 | set_default_spectre(kvm); | 158 | set_default_spectre(kvm); |
| 159 | kvm_arm_init_hypercalls(kvm); | ||
| 159 | 160 | ||
| 160 | return ret; | 161 | return ret; |
| 161 | out_free_stage2_pgd: | 162 | out_free_stage2_pgd: |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
| 20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
| 21 | #include <kvm/arm_psci.h> | 21 | #include <kvm/arm_hypercalls.h> |
| 22 | #include <asm/cputype.h> | 22 | #include <asm/cputype.h> |
| 23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
| 24 | #include <asm/fpsimd.h> | 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 | switch (reg->id & KVM_REG_ARM_COPROC_MASK) { | 757 | switch (reg->id & KVM_REG_ARM_COPROC_MASK) { |
| 758 | case KVM_REG_ARM_CORE: return get_core_reg(vcpu, reg); | 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 | case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg); | 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 | switch (reg->id & KVM_REG_ARM_COPROC_MASK) { | 777 | switch (reg->id & KVM_REG_ARM_COPROC_MASK) { |
| 776 | case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg); | 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 | case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg); | 782 | case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg); |
| 779 | } | 783 | } |
| 780 | 784 | ||
| @@ -9,6 +9,13 @@ · 8 unmodified lines | |||
| 9 | #include <kvm/arm_hypercalls.h> | 9 | #include <kvm/arm_hypercalls.h> |
| 10 | #include <kvm/arm_psci.h> | 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 | static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) | 19 | static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) |
| 13 | { | 20 | { |
| 14 | struct system_time_snapshot systime_snapshot; | 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 | val[3] = lower_32_bits(cycles); | 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 | int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) | 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 | u32 func_id = smccc_get_function(vcpu); | 127 | u32 func_id = smccc_get_function(vcpu); |
| 64 | u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; | 128 | u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; |
| 65 | u32 feature; | 129 | u32 feature; |
| 66 | gpa_t gpa; | 130 | gpa_t gpa; |
| 67 | 131 | ||
| 132 | if (!kvm_hvc_call_allowed(vcpu, func_id)) | ||
| 133 | goto out; | ||
| 134 | |||
| 68 | switch (func_id) { | 135 | switch (func_id) { |
| 69 | case ARM_SMCCC_VERSION_FUNC_ID: | 136 | case ARM_SMCCC_VERSION_FUNC_ID: |
| 70 | val[0] = ARM_SMCCC_VERSION_1_1; | 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 | break; | 188 | break; |
| 122 | case ARM_SMCCC_HV_PV_TIME_FEATURES: | 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 | break; | 193 | break; |
| 125 | } | 194 | } |
| 126 | break; | 195 | break; |
| @@ -139,8 +208,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) · 12 unmodified lines | |||
| 139 | val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; | 208 | val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3; |
| 140 | break; | 209 | break; |
| 141 | case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: | 210 | case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID: |
| 142 | val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES); | 211 | val[0] = smccc_feat->vendor_hyp_bmap; |
| 143 | val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP); | ||
| 144 | break; | 212 | break; |
| 145 | case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: | 213 | case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: |
| 146 | kvm_ptp_get_time(vcpu, val); | 214 | kvm_ptp_get_time(vcpu, val); |
| @@ -155,6 +223,259 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) · 8 unmodified lines | |||
| 155 | return kvm_psci_call(vcpu); | 223 | return kvm_psci_call(vcpu); |
| 156 | } | 224 | } |
| 157 | 225 | ||
| 226 | out: | ||
| 158 | smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); | 227 | smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]); |
| 159 | return 1; | 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 | return -EINVAL; | 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 | vcpu_set_reg(vcpu, 3, a3); | 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 | #endif | 51 | #endif |
| @@ -39,11 +39,4 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu) · 38 unmodified lines | |||
| 39 | 39 | ||
| 40 | int kvm_psci_call(struct kvm_vcpu *vcpu); | 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 | #endif /* __KVM_ARM_PSCI_H__ */ | 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 | /aarch64/arch_timer | 2 | /aarch64/arch_timer |
| 3 | /aarch64/debug-exceptions | 3 | /aarch64/debug-exceptions |
| 4 | /aarch64/get-reg-list | 4 | /aarch64/get-reg-list |
| 5 | /aarch64/psci_cpu_on_test | 5 | /aarch64/hypercalls |
| 6 | /aarch64/psci_test | ||
| 6 | /aarch64/vcpu_width_config | 7 | /aarch64/vcpu_width_config |
| 7 | /aarch64/vgic_init | 8 | /aarch64/vgic_init |
| 8 | /aarch64/vgic_irq | 9 | /aarch64/vgic_irq |
| @@ -105,7 +105,8 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test · 104 unmodified lines | |||
| 105 | TEST_GEN_PROGS_aarch64 += aarch64/arch_timer | 105 | TEST_GEN_PROGS_aarch64 += aarch64/arch_timer |
| 106 | TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions | 106 | TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions |
| 107 | TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list | 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 | TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config | 110 | TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config |
| 110 | TEST_GEN_PROGS_aarch64 += aarch64/vgic_init | 111 | TEST_GEN_PROGS_aarch64 += aarch64/vgic_init |
| 111 | TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq | 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 | "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id); | 294 | "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id); |
| 295 | printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff); | 295 | printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff); |
| 296 | break; | 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 | case KVM_REG_ARM64_SVE: | 302 | case KVM_REG_ARM64_SVE: |
| 298 | if (has_cap(c, KVM_CAP_ARM_SVE)) | 303 | if (has_cap(c, KVM_CAP_ARM_SVE)) |
| 299 | printf("\t%s,\n", sve_id_to_str(c, id)); | 304 | printf("\t%s,\n", sve_id_to_str(c, id)); |
| @@ -692,6 +697,9 @@ static __u64 base_regs[] = { · 392 unmodified lines | |||
| 692 | KVM_REG_ARM_FW_REG(1), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 */ | 697 | KVM_REG_ARM_FW_REG(1), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1 */ |
| 693 | KVM_REG_ARM_FW_REG(2), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 */ | 698 | KVM_REG_ARM_FW_REG(2), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2 */ |
| 694 | KVM_REG_ARM_FW_REG(3), /* KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3 */ | 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 | ARM64_SYS_REG(3, 3, 14, 3, 1), /* CNTV_CTL_EL0 */ | 703 | ARM64_SYS_REG(3, 3, 14, 3, 1), /* CNTV_CTL_EL0 */ |
| 696 | ARM64_SYS_REG(3, 3, 14, 3, 2), /* CNTV_CVAL_EL0 */ | 704 | ARM64_SYS_REG(3, 3, 14, 3, 2), /* CNTV_CVAL_EL0 */ |
| 697 | ARM64_SYS_REG(3, 3, 14, 0, 2), | 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 | static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr, | 26 | static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr, |
| 27 | uint64_t context_id) | 27 | uint64_t context_id) |
| 28 | { | 28 | { |
| 29 | register uint64_t x0 asm("x0") = PSCI_0_2_FN64_CPU_ON; | 29 | struct arm_smccc_res res; |
| 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; | ||
| 33 | 30 | ||
| 34 | asm("hvc #0" | 31 | smccc_hvc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id, |
| 35 | : "=r"(x0) | 32 | 0, 0, 0, 0, &res); |
| 36 | : "r"(x0), "r"(x1), "r"(x2), "r"(x3) | ||
| 37 | : "memory"); | ||
| 38 | 33 | ||
| 39 | return x0; | 34 | return res.a0; |
| 40 | } | 35 | } |
| 41 | 36 | ||
| 42 | static uint64_t psci_affinity_info(uint64_t target_affinity, | 37 | static uint64_t psci_affinity_info(uint64_t target_affinity, |
| 43 | uint64_t lowest_affinity_level) | 38 | uint64_t lowest_affinity_level) |
| 44 | { | 39 | { |
| 45 | register uint64_t x0 asm("x0") = PSCI_0_2_FN64_AFFINITY_INFO; | 40 | struct arm_smccc_res res; |
| 46 | register uint64_t x1 asm("x1") = target_affinity; | ||
| 47 | register uint64_t x2 asm("x2") = lowest_affinity_level; | ||
| 48 | 41 | ||
| 49 | asm("hvc #0" | 42 | smccc_hvc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level, |
| 50 | : "=r"(x0) | 43 | 0, 0, 0, 0, 0, &res); |
| 51 | : "r"(x0), "r"(x1), "r"(x2) | ||
| 52 | : "memory"); | ||
| 53 | 44 | ||
| 54 | return x0; | 45 | return res.a0; |
| 55 | } | 46 | } |
| 56 | 47 | ||
| 57 | static void guest_main(uint64_t target_cpu) | 48 | static void guest_main(uint64_t target_cpu) |
| @@ -185,4 +185,26 @@ static inline void local_irq_disable(void) · 184 unmodified lines | |||
| 185 | asm volatile("msr daifset, #3" : : : "memory"); | 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 | #endif /* SELFTEST_KVM_PROCESSOR_H */ | 210 | #endif /* SELFTEST_KVM_PROCESSOR_H */ |
| @@ -500,3 +500,28 @@ void __attribute__((constructor)) init_guest_modes(void) · 499 unmodified lines | |||
| 500 | { | 500 | { |
| 501 | guest_modes_append_default(); | 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 | static int64_t smccc(uint32_t func, uint64_t arg) | 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( | 123 | smccc_hvc(func, arg, 0, 0, 0, 0, 0, 0, &res); |
| 124 | "mov w0, %w1\n" | 124 | return res.a0; |
| 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; | ||
| 132 | } | 125 | } |
| 133 | 126 | ||
| 134 | static void check_status(struct st_time *st) | 127 | static void check_status(struct st_time *st) |