Skip to content

Commit fb88707

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: Use a maple tree to represent the SMCCC filter
Maple tree is an efficient B-tree implementation that is intended for storing non-overlapping intervals. Such a data structure is a good fit for the SMCCC filter as it is desirable to sparsely allocate the 32 bit function ID space. To that end, add a maple tree to kvm_arch and correctly init/teardown along with the VM. Wire in a test against the hypercall filter for HVCs which does nothing until the controls are exposed to userspace. Signed-off-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20230404154050.2270077-8-oliver.upton@linux.dev
1 parent a8308b3 commit fb88707

4 files changed

Lines changed: 64 additions & 1 deletion

File tree

arch/arm64/include/asm/kvm_host.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/types.h>
1717
#include <linux/jump_label.h>
1818
#include <linux/kvm_types.h>
19+
#include <linux/maple_tree.h>
1920
#include <linux/percpu.h>
2021
#include <linux/psci.h>
2122
#include <asm/arch_gicv3.h>
@@ -221,7 +222,8 @@ struct kvm_arch {
221222
#define KVM_ARCH_FLAG_EL1_32BIT 4
222223
/* PSCI SYSTEM_SUSPEND enabled for the guest */
223224
#define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 5
224-
225+
/* SMCCC filter initialized for the VM */
226+
#define KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED 6
225227
unsigned long flags;
226228

227229
/*
@@ -242,6 +244,7 @@ struct kvm_arch {
242244

243245
/* Hypercall features firmware registers' descriptor */
244246
struct kvm_smccc_features smccc_feat;
247+
struct maple_tree smccc_filter;
245248

246249
/*
247250
* For an untrusted host VM, 'pkvm.handle' is used to lookup

arch/arm64/kvm/arm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
192192
kvm_destroy_vcpus(kvm);
193193

194194
kvm_unshare_hyp(kvm, kvm + 1);
195+
196+
kvm_arm_teardown_hypercalls(kvm);
195197
}
196198

197199
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)

arch/arm64/kvm/hypercalls.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,58 @@ static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id)
121121
}
122122
}
123123

124+
#define SMCCC_ARCH_RANGE_BEGIN ARM_SMCCC_VERSION_FUNC_ID
125+
#define SMCCC_ARCH_RANGE_END \
126+
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
127+
ARM_SMCCC_SMC_32, \
128+
0, ARM_SMCCC_FUNC_MASK)
129+
130+
static void init_smccc_filter(struct kvm *kvm)
131+
{
132+
int r;
133+
134+
mt_init(&kvm->arch.smccc_filter);
135+
136+
/*
137+
* Prevent userspace from handling any SMCCC calls in the architecture
138+
* range, avoiding the risk of misrepresenting Spectre mitigation status
139+
* to the guest.
140+
*/
141+
r = mtree_insert_range(&kvm->arch.smccc_filter,
142+
SMCCC_ARCH_RANGE_BEGIN, SMCCC_ARCH_RANGE_END,
143+
xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
144+
GFP_KERNEL_ACCOUNT);
145+
WARN_ON_ONCE(r);
146+
}
147+
148+
static u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id)
149+
{
150+
unsigned long idx = func_id;
151+
void *val;
152+
153+
if (!test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags))
154+
return KVM_SMCCC_FILTER_HANDLE;
155+
156+
/*
157+
* But where's the error handling, you say?
158+
*
159+
* mt_find() returns NULL if no entry was found, which just so happens
160+
* to match KVM_SMCCC_FILTER_HANDLE.
161+
*/
162+
val = mt_find(&kvm->arch.smccc_filter, &idx, idx);
163+
return xa_to_value(val);
164+
}
165+
124166
static u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id)
125167
{
168+
/*
169+
* Intervening actions in the SMCCC filter take precedence over the
170+
* pseudo-firmware register bitmaps.
171+
*/
172+
u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id);
173+
if (action != KVM_SMCCC_FILTER_HANDLE)
174+
return action;
175+
126176
if (kvm_smccc_test_fw_bmap(vcpu, func_id) ||
127177
kvm_smccc_default_allowed(func_id))
128178
return KVM_SMCCC_FILTER_HANDLE;
@@ -263,6 +313,13 @@ void kvm_arm_init_hypercalls(struct kvm *kvm)
263313
smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES;
264314
smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES;
265315
smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES;
316+
317+
init_smccc_filter(kvm);
318+
}
319+
320+
void kvm_arm_teardown_hypercalls(struct kvm *kvm)
321+
{
322+
mtree_destroy(&kvm->arch.smccc_filter);
266323
}
267324

268325
int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)

include/kvm/arm_hypercalls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu,
4343
struct kvm_one_reg;
4444

4545
void kvm_arm_init_hypercalls(struct kvm *kvm);
46+
void kvm_arm_teardown_hypercalls(struct kvm *kvm);
4647
int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu);
4748
int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
4849
int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);

0 commit comments

Comments
 (0)