Skip to content

Commit 4f5defa

Browse files
committed
KVM: SEV: introduce KVM_SEV_INIT2 operation
The idea that no parameter would ever be necessary when enabling SEV or SEV-ES for a VM was decidedly optimistic. In fact, in some sense it's already a parameter whether SEV or SEV-ES is desired. Another possible source of variability is the desired set of VMSA features, as that affects the measurement of the VM's initial state and cannot be changed arbitrarily by the hypervisor. Create a new sub-operation for KVM_MEMORY_ENCRYPT_OP that can take a struct, and put the new op to work by including the VMSA features as a field of the struct. The existing KVM_SEV_INIT and KVM_SEV_ES_INIT use the full set of supported VMSA features for backwards compatibility. The struct also includes the usual bells and whistles for future extensibility: a flags field that must be zero for now, and some padding at the end. Signed-off-by: Paolo Bonzini <[email protected]> Message-ID: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent eb44418 commit 4f5defa

File tree

3 files changed

+92
-10
lines changed

3 files changed

+92
-10
lines changed

Documentation/virt/kvm/x86/amd-memory-encryption.rst

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,49 @@ are defined in ``<linux/psp-dev.h>``.
7676
KVM implements the following commands to support common lifecycle events of SEV
7777
guests, such as launching, running, snapshotting, migrating and decommissioning.
7878

79-
1. KVM_SEV_INIT
80-
---------------
79+
1. KVM_SEV_INIT2
80+
----------------
8181

82-
The KVM_SEV_INIT command is used by the hypervisor to initialize the SEV platform
82+
The KVM_SEV_INIT2 command is used by the hypervisor to initialize the SEV platform
8383
context. In a typical workflow, this command should be the first command issued.
8484

85+
For this command to be accepted, either KVM_X86_SEV_VM or KVM_X86_SEV_ES_VM
86+
must have been passed to the KVM_CREATE_VM ioctl. A virtual machine created
87+
with those machine types in turn cannot be run until KVM_SEV_INIT2 is invoked.
88+
89+
Parameters: struct kvm_sev_init (in)
8590

8691
Returns: 0 on success, -negative on error
8792

93+
::
94+
95+
struct kvm_sev_init {
96+
__u64 vmsa_features; /* initial value of features field in VMSA */
97+
__u32 flags; /* must be 0 */
98+
__u32 pad[9];
99+
};
100+
101+
It is an error if the hypervisor does not support any of the bits that
102+
are set in ``flags`` or ``vmsa_features``. ``vmsa_features`` must be
103+
0 for SEV virtual machines, as they do not have a VMSA.
104+
105+
This command replaces the deprecated KVM_SEV_INIT and KVM_SEV_ES_INIT commands.
106+
The commands did not have any parameters (the ```data``` field was unused) and
107+
only work for the KVM_X86_DEFAULT_VM machine type (0).
108+
109+
They behave as if:
110+
111+
* the VM type is KVM_X86_SEV_VM for KVM_SEV_INIT, or KVM_X86_SEV_ES_VM for
112+
KVM_SEV_ES_INIT
113+
114+
* the ``flags`` and ``vmsa_features`` fields of ``struct kvm_sev_init`` are
115+
set to zero
116+
117+
If the ``KVM_X86_SEV_VMSA_FEATURES`` attribute does not exist, the hypervisor only
118+
supports KVM_SEV_INIT and KVM_SEV_ES_INIT. In that case, note that KVM_SEV_ES_INIT
119+
might set the debug swap VMSA feature (bit 5) depending on the value of the
120+
``debug_swap`` parameter of ``kvm-amd.ko``.
121+
88122
2. KVM_SEV_LAUNCH_START
89123
-----------------------
90124

arch/x86/include/uapi/asm/kvm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,9 @@ enum sev_cmd_id {
694694
/* Guest Migration Extension */
695695
KVM_SEV_SEND_CANCEL,
696696

697+
/* Second time is the charm; improved versions of the above ioctls. */
698+
KVM_SEV_INIT2,
699+
697700
KVM_SEV_NR_MAX,
698701
};
699702

@@ -705,6 +708,12 @@ struct kvm_sev_cmd {
705708
__u32 sev_fd;
706709
};
707710

711+
struct kvm_sev_init {
712+
__u64 vmsa_features;
713+
__u32 flags;
714+
__u32 pad[9];
715+
};
716+
708717
struct kvm_sev_launch_start {
709718
__u32 handle;
710719
__u32 policy;

arch/x86/kvm/svm/sev.c

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,27 +243,31 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
243243
sev_decommission(handle);
244244
}
245245

246-
static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
246+
static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
247+
struct kvm_sev_init *data,
248+
unsigned long vm_type)
247249
{
248250
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
249251
struct sev_platform_init_args init_args = {0};
252+
bool es_active = vm_type != KVM_X86_SEV_VM;
253+
u64 valid_vmsa_features = es_active ? sev_supported_vmsa_features : 0;
250254
int ret;
251255

252256
if (kvm->created_vcpus)
253257
return -EINVAL;
254258

255-
if (kvm->arch.vm_type != KVM_X86_DEFAULT_VM)
259+
if (data->flags)
260+
return -EINVAL;
261+
262+
if (data->vmsa_features & ~valid_vmsa_features)
256263
return -EINVAL;
257264

258265
if (unlikely(sev->active))
259266
return -EINVAL;
260267

261268
sev->active = true;
262-
sev->es_active = argp->id == KVM_SEV_ES_INIT;
263-
sev->vmsa_features = sev_supported_vmsa_features;
264-
if (sev_supported_vmsa_features)
265-
pr_warn_once("Enabling DebugSwap with KVM_SEV_ES_INIT. "
266-
"This will not work starting with Linux 6.10\n");
269+
sev->es_active = es_active;
270+
sev->vmsa_features = data->vmsa_features;
267271

268272
ret = sev_asid_new(sev);
269273
if (ret)
@@ -293,6 +297,38 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
293297
return ret;
294298
}
295299

300+
static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
301+
{
302+
struct kvm_sev_init data = {
303+
.vmsa_features = 0,
304+
};
305+
unsigned long vm_type;
306+
307+
if (kvm->arch.vm_type != KVM_X86_DEFAULT_VM)
308+
return -EINVAL;
309+
310+
vm_type = (argp->id == KVM_SEV_INIT ? KVM_X86_SEV_VM : KVM_X86_SEV_ES_VM);
311+
return __sev_guest_init(kvm, argp, &data, vm_type);
312+
}
313+
314+
static int sev_guest_init2(struct kvm *kvm, struct kvm_sev_cmd *argp)
315+
{
316+
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
317+
struct kvm_sev_init data;
318+
319+
if (!sev->need_init)
320+
return -EINVAL;
321+
322+
if (kvm->arch.vm_type != KVM_X86_SEV_VM &&
323+
kvm->arch.vm_type != KVM_X86_SEV_ES_VM)
324+
return -EINVAL;
325+
326+
if (copy_from_user(&data, u64_to_user_ptr(argp->data), sizeof(data)))
327+
return -EFAULT;
328+
329+
return __sev_guest_init(kvm, argp, &data, kvm->arch.vm_type);
330+
}
331+
296332
static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error)
297333
{
298334
unsigned int asid = sev_get_asid(kvm);
@@ -1960,6 +1996,9 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp)
19601996
case KVM_SEV_INIT:
19611997
r = sev_guest_init(kvm, &sev_cmd);
19621998
break;
1999+
case KVM_SEV_INIT2:
2000+
r = sev_guest_init2(kvm, &sev_cmd);
2001+
break;
19632002
case KVM_SEV_LAUNCH_START:
19642003
r = sev_launch_start(kvm, &sev_cmd);
19652004
break;

0 commit comments

Comments
 (0)