Skip to content

Commit

Permalink
KVM: Add functions to set GFN to private or shared
Browse files Browse the repository at this point in the history
TDX KVM support needs to track whether GFN is private or shared.  Introduce
functions to set whether GFN is private or shared and pre-allocate memory
for xarray.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
  • Loading branch information
yamahata committed Sep 30, 2022
1 parent 66be339 commit 60ecd05
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
2 changes: 1 addition & 1 deletion arch/x86/kvm/Kconfig
Expand Up @@ -49,7 +49,7 @@ config KVM
select SRCU
select INTERVAL_TREE
select HAVE_KVM_PM_NOTIFIER if PM
select HAVE_KVM_PRIVATE_MEM if X86_64
select HAVE_KVM_PRIVATE_MEM if KVM_MMU_PRIVATE
help
Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent
Expand Down
17 changes: 16 additions & 1 deletion include/linux/kvm_host.h
Expand Up @@ -2294,9 +2294,20 @@ static inline void kvm_handle_signal_exit(struct kvm_vcpu *vcpu)
#define KVM_MEM_ATTR_PRIVATE 0x0002

#ifdef __KVM_HAVE_ARCH_UPDATE_MEM_ATTR
/* memory attr on [start, end) */
int kvm_vm_reserve_mem_attr(struct kvm *kvm, gfn_t start, gfn_t end);
int kvm_vm_set_mem_attr(struct kvm *kvm, int attr, gfn_t start, gfn_t end);
void kvm_arch_update_mem_attr(struct kvm *kvm, unsigned int attr,
gfn_t start, gfn_t end);
#else
static inline int kvm_vm_reserve_mem_attr(struct kvm *kvm, gfn_t start, gfn_t end)
{
return -EOPNOTSUPP;
}
static inline int kvm_vm_set_mem_attr(struct kvm *kvm, int attr, gfn_t start, gfn_t end)
{
return -EOPNOTSUPP;
}
static inline void kvm_arch_update_mem_attr(struct kvm *kvm, unsigned int attr,
gfn_t start, gfn_t end)
{
Expand Down Expand Up @@ -2326,7 +2337,11 @@ static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn)
{
return !xa_load(&kvm->mem_attr_array, gfn);
}

#else
static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn)
{
return false;
}
#endif /* CONFIG_HAVE_KVM_PRIVATE_MEM */

#endif
56 changes: 56 additions & 0 deletions virt/kvm/kvm_main.c
Expand Up @@ -1019,6 +1019,62 @@ static inline void kvm_private_mem_unregister(struct kvm_memory_slot *slot)
inaccessible_unregister_notifier(slot->private_file, &slot->notifier);
}

/*
* Reserve memory for [start, end) so that the next set oepration won't fail
* with -ENOMEM.
*/
int kvm_vm_reserve_mem_attr(struct kvm *kvm, gfn_t start, gfn_t end)
{
int r = 0;
gfn_t gfn;

xa_lock(&kvm->mem_attr_array);
for (gfn = start; gfn < end; gfn++) {
r = __xa_insert(&kvm->mem_attr_array, gfn, NULL, GFP_KERNEL_ACCOUNT);
if (r == -EBUSY)
r = 0;
if (r)
break;
}
xa_unlock(&kvm->mem_attr_array);

return r;
}
EXPORT_SYMBOL_GPL(kvm_vm_reserve_mem_attr);

/* Set memory attr for [start, end) */
int kvm_vm_set_mem_attr(struct kvm *kvm, int attr, gfn_t start, gfn_t end)
{
void *entry;
gfn_t gfn;
int r;

/* By default, the entry is private. */
switch (attr) {
case KVM_MEM_ATTR_PRIVATE:
entry = NULL;
break;
case KVM_MEM_ATTR_SHARED:
entry = xa_mk_value(KVM_MEM_ATTR_SHARED);
break;
default:
WARN_ON_ONCE(1);
return -EINVAL;
}

WARN_ON_ONCE(start >= end);
for (gfn = start; gfn < end; gfn++) {
r = xa_err(xa_store(&kvm->mem_attr_array, gfn, entry,
GFP_KERNEL_ACCOUNT));
if (r)
break;
}
if (start < gfn)
kvm_arch_update_mem_attr(kvm, attr, start, gfn);
return r;
}
EXPORT_SYMBOL_GPL(kvm_vm_set_mem_attr);

#else /* !CONFIG_HAVE_KVM_PRIVATE_MEM */

static inline void kvm_private_mem_register(struct kvm_memory_slot *slot)
Expand Down

0 comments on commit 60ecd05

Please sign in to comment.