Commit 0dbb1123 authored by Ashish Kalra's avatar Ashish Kalra Committed by Paolo Bonzini

KVM: X86: Introduce KVM_HC_MAP_GPA_RANGE hypercall

This hypercall is used by the SEV guest to notify a change in the page
encryption status to the hypervisor. The hypercall should be invoked
only when the encryption attribute is changed from encrypted -> decrypted
and vice versa. By default all guest pages are considered encrypted.

The hypercall exits to userspace to manage the guest shared regions and
integrate with the userspace VMM's migration code.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: x86@kernel.org
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Reviewed-by: default avatarSteve Rutherford <srutherford@google.com>
Signed-off-by: default avatarBrijesh Singh <brijesh.singh@amd.com>
Signed-off-by: default avatarAshish Kalra <ashish.kalra@amd.com>
Co-developed-by: default avatarSean Christopherson <seanjc@google.com>
Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Co-developed-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Message-Id: <90778988e1ee01926ff9cac447aacb745f954c8c.1623174621.git.ashish.kalra@amd.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent e3cb6fa0
...@@ -6950,3 +6950,22 @@ guest according to the bits Hyper-V CPUID feature leaves. Otherwise, all ...@@ -6950,3 +6950,22 @@ guest according to the bits Hyper-V CPUID feature leaves. Otherwise, all
currently implmented Hyper-V features are provided unconditionally when currently implmented Hyper-V features are provided unconditionally when
Hyper-V identification is set in the HYPERV_CPUID_INTERFACE (0x40000001) Hyper-V identification is set in the HYPERV_CPUID_INTERFACE (0x40000001)
leaf. leaf.
8.34 KVM_CAP_EXIT_HYPERCALL
---------------------------
:Capability: KVM_CAP_EXIT_HYPERCALL
:Architectures: x86
:Type: vm
This capability, if enabled, will cause KVM to exit to userspace
with KVM_EXIT_HYPERCALL exit reason to process some hypercalls.
Calling KVM_CHECK_EXTENSION for this capability will return a bitmask
of hypercalls that can be configured to exit to userspace.
Right now, the only such hypercall is KVM_HC_MAP_GPA_RANGE.
The argument to KVM_ENABLE_CAP is also a bitmask, and must be a subset
of the result of KVM_CHECK_EXTENSION. KVM will forward to userspace
the hypercalls whose corresponding bit is in the argument, and return
ENOSYS for the others.
...@@ -96,6 +96,13 @@ KVM_FEATURE_MSI_EXT_DEST_ID 15 guest checks this feature bit ...@@ -96,6 +96,13 @@ KVM_FEATURE_MSI_EXT_DEST_ID 15 guest checks this feature bit
before using extended destination before using extended destination
ID bits in MSI address bits 11-5. ID bits in MSI address bits 11-5.
KVM_FEATURE_HC_MAP_GPA_RANGE 16 guest checks this feature bit before
using the map gpa range hypercall
to notify the page state change
KVM_FEATURE_MIGRATION_CONTROL 17 guest checks this feature bit before
using MSR_KVM_MIGRATION_CONTROL
KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 24 host will warn if no guest-side KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 24 host will warn if no guest-side
per-cpu warps are expected in per-cpu warps are expected in
kvmclock kvmclock
......
...@@ -169,3 +169,24 @@ a0: destination APIC ID ...@@ -169,3 +169,24 @@ a0: destination APIC ID
:Usage example: When sending a call-function IPI-many to vCPUs, yield if :Usage example: When sending a call-function IPI-many to vCPUs, yield if
any of the IPI target vCPUs was preempted. any of the IPI target vCPUs was preempted.
8. KVM_HC_MAP_GPA_RANGE
-------------------------
:Architecture: x86
:Status: active
:Purpose: Request KVM to map a GPA range with the specified attributes.
a0: the guest physical address of the start page
a1: the number of (4kb) pages (must be contiguous in GPA space)
a2: attributes
Where 'attributes' :
* bits 3:0 - preferred page size encoding 0 = 4kb, 1 = 2mb, 2 = 1gb, etc...
* bit 4 - plaintext = 0, encrypted = 1
* bits 63:5 - reserved (must be zero)
**Implementation note**: this hypercall is implemented in userspace via
the KVM_CAP_EXIT_HYPERCALL capability. Userspace must enable that capability
before advertising KVM_FEATURE_HC_MAP_GPA_RANGE in the guest CPUID. In
addition, if the guest supports KVM_FEATURE_MIGRATION_CONTROL, userspace
must also set up an MSR filter to process writes to MSR_KVM_MIGRATION_CONTROL.
...@@ -376,3 +376,16 @@ data: ...@@ -376,3 +376,16 @@ data:
write '1' to bit 0 of the MSR, this causes the host to re-scan its queue write '1' to bit 0 of the MSR, this causes the host to re-scan its queue
and check if there are more notifications pending. The MSR is available and check if there are more notifications pending. The MSR is available
if KVM_FEATURE_ASYNC_PF_INT is present in CPUID. if KVM_FEATURE_ASYNC_PF_INT is present in CPUID.
MSR_KVM_MIGRATION_CONTROL:
0x4b564d08
data:
This MSR is available if KVM_FEATURE_MIGRATION_CONTROL is present in
CPUID. Bit 0 represents whether live migration of the guest is allowed.
When a guest is started, bit 0 will be 0 if the guest has encrypted
memory and 1 if the guest does not have encrypted memory. If the
guest is communicating page encryption status to the host using the
``KVM_HC_MAP_GPA_RANGE`` hypercall, it can set bit 0 in this MSR to
allow live migration of the guest.
...@@ -1087,6 +1087,8 @@ struct kvm_arch { ...@@ -1087,6 +1087,8 @@ struct kvm_arch {
u32 user_space_msr_mask; u32 user_space_msr_mask;
struct kvm_x86_msr_filter __rcu *msr_filter; struct kvm_x86_msr_filter __rcu *msr_filter;
u32 hypercall_exit_enabled;
/* Guest can access the SGX PROVISIONKEY. */ /* Guest can access the SGX PROVISIONKEY. */
bool sgx_provisioning_allowed; bool sgx_provisioning_allowed;
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#define KVM_FEATURE_PV_SCHED_YIELD 13 #define KVM_FEATURE_PV_SCHED_YIELD 13
#define KVM_FEATURE_ASYNC_PF_INT 14 #define KVM_FEATURE_ASYNC_PF_INT 14
#define KVM_FEATURE_MSI_EXT_DEST_ID 15 #define KVM_FEATURE_MSI_EXT_DEST_ID 15
#define KVM_FEATURE_HC_MAP_GPA_RANGE 16
#define KVM_FEATURE_MIGRATION_CONTROL 17
#define KVM_HINTS_REALTIME 0 #define KVM_HINTS_REALTIME 0
...@@ -54,6 +56,7 @@ ...@@ -54,6 +56,7 @@
#define MSR_KVM_POLL_CONTROL 0x4b564d05 #define MSR_KVM_POLL_CONTROL 0x4b564d05
#define MSR_KVM_ASYNC_PF_INT 0x4b564d06 #define MSR_KVM_ASYNC_PF_INT 0x4b564d06
#define MSR_KVM_ASYNC_PF_ACK 0x4b564d07 #define MSR_KVM_ASYNC_PF_ACK 0x4b564d07
#define MSR_KVM_MIGRATION_CONTROL 0x4b564d08
struct kvm_steal_time { struct kvm_steal_time {
__u64 steal; __u64 steal;
...@@ -90,6 +93,16 @@ struct kvm_clock_pairing { ...@@ -90,6 +93,16 @@ struct kvm_clock_pairing {
/* MSR_KVM_ASYNC_PF_INT */ /* MSR_KVM_ASYNC_PF_INT */
#define KVM_ASYNC_PF_VEC_MASK GENMASK(7, 0) #define KVM_ASYNC_PF_VEC_MASK GENMASK(7, 0)
/* MSR_KVM_MIGRATION_CONTROL */
#define KVM_MIGRATION_READY (1 << 0)
/* KVM_HC_MAP_GPA_RANGE */
#define KVM_MAP_GPA_RANGE_PAGE_SZ_4K 0
#define KVM_MAP_GPA_RANGE_PAGE_SZ_2M (1 << 0)
#define KVM_MAP_GPA_RANGE_PAGE_SZ_1G (1 << 1)
#define KVM_MAP_GPA_RANGE_ENC_STAT(n) (n << 4)
#define KVM_MAP_GPA_RANGE_ENCRYPTED KVM_MAP_GPA_RANGE_ENC_STAT(1)
#define KVM_MAP_GPA_RANGE_DECRYPTED KVM_MAP_GPA_RANGE_ENC_STAT(0)
/* Operations for KVM_HC_MMU_OP */ /* Operations for KVM_HC_MMU_OP */
#define KVM_MMU_OP_WRITE_PTE 1 #define KVM_MMU_OP_WRITE_PTE 1
......
...@@ -103,6 +103,8 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE); ...@@ -103,6 +103,8 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS; static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS;
#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE)
#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \ #define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \
KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK) KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
...@@ -3996,6 +3998,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) ...@@ -3996,6 +3998,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_SREGS2: case KVM_CAP_SREGS2:
r = 1; r = 1;
break; break;
case KVM_CAP_EXIT_HYPERCALL:
r = KVM_EXIT_HYPERCALL_VALID_MASK;
break;
case KVM_CAP_SET_GUEST_DEBUG2: case KVM_CAP_SET_GUEST_DEBUG2:
return KVM_GUESTDBG_VALID_MASK; return KVM_GUESTDBG_VALID_MASK;
#ifdef CONFIG_KVM_XEN #ifdef CONFIG_KVM_XEN
...@@ -5622,6 +5627,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, ...@@ -5622,6 +5627,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
if (kvm_x86_ops.vm_copy_enc_context_from) if (kvm_x86_ops.vm_copy_enc_context_from)
r = kvm_x86_ops.vm_copy_enc_context_from(kvm, cap->args[0]); r = kvm_x86_ops.vm_copy_enc_context_from(kvm, cap->args[0]);
return r; return r;
case KVM_CAP_EXIT_HYPERCALL:
if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) {
r = -EINVAL;
break;
}
kvm->arch.hypercall_exit_enabled = cap->args[0];
r = 0;
break;
default: default:
r = -EINVAL; r = -EINVAL;
break; break;
...@@ -8548,6 +8561,17 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id) ...@@ -8548,6 +8561,17 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id)
return; return;
} }
static int complete_hypercall_exit(struct kvm_vcpu *vcpu)
{
u64 ret = vcpu->run->hypercall.ret;
if (!is_64_bit_mode(vcpu))
ret = (u32)ret;
kvm_rax_write(vcpu, ret);
++vcpu->stat.hypercalls;
return kvm_skip_emulated_instruction(vcpu);
}
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
{ {
unsigned long nr, a0, a1, a2, a3, ret; unsigned long nr, a0, a1, a2, a3, ret;
...@@ -8613,6 +8637,28 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) ...@@ -8613,6 +8637,28 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
kvm_sched_yield(vcpu, a0); kvm_sched_yield(vcpu, a0);
ret = 0; ret = 0;
break; break;
case KVM_HC_MAP_GPA_RANGE: {
u64 gpa = a0, npages = a1, attrs = a2;
ret = -KVM_ENOSYS;
if (!(vcpu->kvm->arch.hypercall_exit_enabled & (1 << KVM_HC_MAP_GPA_RANGE)))
break;
if (!PAGE_ALIGNED(gpa) || !npages ||
gpa_to_gfn(gpa) + npages <= gpa_to_gfn(gpa)) {
ret = -KVM_EINVAL;
break;
}
vcpu->run->exit_reason = KVM_EXIT_HYPERCALL;
vcpu->run->hypercall.nr = KVM_HC_MAP_GPA_RANGE;
vcpu->run->hypercall.args[0] = gpa;
vcpu->run->hypercall.args[1] = npages;
vcpu->run->hypercall.args[2] = attrs;
vcpu->run->hypercall.longmode = op_64_bit;
vcpu->arch.complete_userspace_io = complete_hypercall_exit;
return 0;
}
default: default:
ret = -KVM_ENOSYS; ret = -KVM_ENOSYS;
break; break;
......
...@@ -1085,6 +1085,7 @@ struct kvm_ppc_resize_hpt { ...@@ -1085,6 +1085,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_PTP_KVM 198 #define KVM_CAP_PTP_KVM 198
#define KVM_CAP_HYPERV_ENFORCE_CPUID 199 #define KVM_CAP_HYPERV_ENFORCE_CPUID 199
#define KVM_CAP_SREGS2 200 #define KVM_CAP_SREGS2 200
#define KVM_CAP_EXIT_HYPERCALL 201
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define KVM_HC_CLOCK_PAIRING 9 #define KVM_HC_CLOCK_PAIRING 9
#define KVM_HC_SEND_IPI 10 #define KVM_HC_SEND_IPI 10
#define KVM_HC_SCHED_YIELD 11 #define KVM_HC_SCHED_YIELD 11
#define KVM_HC_MAP_GPA_RANGE 12
/* /*
* hypercalls use architecture specific * hypercalls use architecture specific
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment