Message ID | 20180308124901.83533-9-brijesh.singh@amd.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, Mar 08, 2018 at 06:48:41AM -0600, Brijesh Singh wrote: > Add a new memory encryption object 'sev-guest'. The object will be used > to create enrypted VMs on AMD EPYC CPU. The object provides the properties > to pass guest owner's public Diffie-hellman key, guest policy and session > information required to create the memory encryption context within the > SEV firmware. > > e.g to launch SEV guest > # $QEMU \ > -object sev-guest,id=sev0 \ > -machine ....,memory-encryption=sev0 > > Cc: Paolo Bonzini <pbonzini@redhat.com> > Cc: Richard Henderson <rth@twiddle.net> > Cc: Eduardo Habkost <ehabkost@redhat.com> > Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> > diff --git a/qemu-options.hx b/qemu-options.hx > index 4c280142c52c..6113bce08a8c 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -4353,6 +4353,50 @@ contents of @code{iv.b64} to the second secret > data=$SECRET,iv=$(<iv.b64) > @end example > > +@item -object sev-guest,id=@var{id},cbitpos=@var{cbitpos},reduced-phys-bits=@var{val},[sev-device=@var{string},policy=@var{policy},handle=@var{handle},dh-cert-file=@var{file},session-file=@var{file}] > + > +Create a Secure Encrypted Virtualization (SEV) guest object, which can be used > +to provide the guest memory encryption support on AMD processors. > + > +When memory encryption is enabled, one of the physical address bit (aka the > +C-bit) is utilized to mark if a memory page is protected. The @option{cbitpos} > +is used to provide the C-bit position. The C-bit position is Host family dependent > +hence user must provide this value. On EPYC, the value should be 47. > + > +When memory encryption is enabled, we loose certain bits in physical address space. > +The @option{reduced-phys-bits} is used to provide the number of bits we loose in > +physical address space. Similar to C-bit, the value is Host family dependent. > +On EPYC, the value should be 5. Is it valid to specify a different value for either of these properties ? eg what happens if I pass cbitpos=45 instead of 47 on an EPYC host ? In particular I thinking about possible migration scenario, where EPYC uses 47 by default but some $NEXT AMD CPU uses 48 by default. In that case we might want to use '47' on both CPUs if we need ability to live migrate between different host CPU generations. Would that be valid ? On the flip side, if the value really it strictly tied to the host CPU family and no deviation is permitted, could the kernel not just pick the right value automatically avoiding the config option ? Regards, Daniel
On 3/8/18 10:49 AM, Daniel P. Berrangé wrote: > On Thu, Mar 08, 2018 at 06:48:41AM -0600, Brijesh Singh wrote: >> Add a new memory encryption object 'sev-guest'. The object will be used >> to create enrypted VMs on AMD EPYC CPU. The object provides the properties >> to pass guest owner's public Diffie-hellman key, guest policy and session >> information required to create the memory encryption context within the >> SEV firmware. >> >> e.g to launch SEV guest >> # $QEMU \ >> -object sev-guest,id=sev0 \ >> -machine ....,memory-encryption=sev0 >> >> Cc: Paolo Bonzini <pbonzini@redhat.com> >> Cc: Richard Henderson <rth@twiddle.net> >> Cc: Eduardo Habkost <ehabkost@redhat.com> >> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> > >> diff --git a/qemu-options.hx b/qemu-options.hx >> index 4c280142c52c..6113bce08a8c 100644 >> --- a/qemu-options.hx >> +++ b/qemu-options.hx >> @@ -4353,6 +4353,50 @@ contents of @code{iv.b64} to the second secret >> data=$SECRET,iv=$(<iv.b64) >> @end example >> >> +@item -object sev-guest,id=@var{id},cbitpos=@var{cbitpos},reduced-phys-bits=@var{val},[sev-device=@var{string},policy=@var{policy},handle=@var{handle},dh-cert-file=@var{file},session-file=@var{file}] >> + >> +Create a Secure Encrypted Virtualization (SEV) guest object, which can be used >> +to provide the guest memory encryption support on AMD processors. >> + >> +When memory encryption is enabled, one of the physical address bit (aka the >> +C-bit) is utilized to mark if a memory page is protected. The @option{cbitpos} >> +is used to provide the C-bit position. The C-bit position is Host family dependent >> +hence user must provide this value. On EPYC, the value should be 47. >> + >> +When memory encryption is enabled, we loose certain bits in physical address space. >> +The @option{reduced-phys-bits} is used to provide the number of bits we loose in >> +physical address space. Similar to C-bit, the value is Host family dependent. >> +On EPYC, the value should be 5. > Is it valid to specify a different value for either of these properties ? > eg what happens if I pass cbitpos=45 instead of 47 on an EPYC host ? On EPYC, passing anything other than 47 will trigger error during SEV guest initialization. The value of Cbit position is host dependent, the value is readonly and can be obtained through the host CPUID. The cbitpos must be same between guest and host. Please note that the pte's in guest page table will need to use the cbitpos information to mark the pages as encrypted. If cbit position given to the guest is different from the host then guest will fail to execute. > > In particular I thinking about possible migration scenario, where EPYC > uses 47 by default but some $NEXT AMD CPU uses 48 by default. In that > case we might want to use '47' on both CPUs if we need ability to live > migrate between different host CPU generations. Would that be valid ? We will not be able to migrate SEV guests if cbit position does not match between the source and destination hosts. Since during migration, the destination guest is launched with same QEMU cli as source hence cbitpos check in QEMU will catch it and fail the new launch. Optionally, user can call query-sev-capabilities on both source and destination to see if cbitpos is compatible before attempting to migrate the guest. > On the flip side, if the value really it strictly tied to the host > CPU family and no deviation is permitted, could the kernel not just > pick the right value automatically avoiding the config option ? > I think doing so will be an issue for the migration. Consider your above use case, a SEV guest is running on EPYC with cbitpos=47 and if we migrate to some $NEXT AMD CPU which uses need to use cbitpos=48 and we will fail to resume the guest on destination after migrating. > > Regards, > Daniel
On Thu, Mar 08, 2018 at 04:22:52PM -0600, Brijesh Singh wrote: > > > On 3/8/18 10:49 AM, Daniel P. Berrangé wrote: > > On Thu, Mar 08, 2018 at 06:48:41AM -0600, Brijesh Singh wrote: > >> Add a new memory encryption object 'sev-guest'. The object will be used > >> to create enrypted VMs on AMD EPYC CPU. The object provides the properties > >> to pass guest owner's public Diffie-hellman key, guest policy and session > >> information required to create the memory encryption context within the > >> SEV firmware. > >> > >> e.g to launch SEV guest > >> # $QEMU \ > >> -object sev-guest,id=sev0 \ > >> -machine ....,memory-encryption=sev0 > >> > >> Cc: Paolo Bonzini <pbonzini@redhat.com> > >> Cc: Richard Henderson <rth@twiddle.net> > >> Cc: Eduardo Habkost <ehabkost@redhat.com> > >> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> > > > >> diff --git a/qemu-options.hx b/qemu-options.hx > >> index 4c280142c52c..6113bce08a8c 100644 > >> --- a/qemu-options.hx > >> +++ b/qemu-options.hx > >> @@ -4353,6 +4353,50 @@ contents of @code{iv.b64} to the second secret > >> data=$SECRET,iv=$(<iv.b64) > >> @end example > >> > >> +@item -object sev-guest,id=@var{id},cbitpos=@var{cbitpos},reduced-phys-bits=@var{val},[sev-device=@var{string},policy=@var{policy},handle=@var{handle},dh-cert-file=@var{file},session-file=@var{file}] > >> + > >> +Create a Secure Encrypted Virtualization (SEV) guest object, which can be used > >> +to provide the guest memory encryption support on AMD processors. > >> + > >> +When memory encryption is enabled, one of the physical address bit (aka the > >> +C-bit) is utilized to mark if a memory page is protected. The @option{cbitpos} > >> +is used to provide the C-bit position. The C-bit position is Host family dependent > >> +hence user must provide this value. On EPYC, the value should be 47. > >> + > >> +When memory encryption is enabled, we loose certain bits in physical address space. > >> +The @option{reduced-phys-bits} is used to provide the number of bits we loose in > >> +physical address space. Similar to C-bit, the value is Host family dependent. > >> +On EPYC, the value should be 5. > > Is it valid to specify a different value for either of these properties ? > > eg what happens if I pass cbitpos=45 instead of 47 on an EPYC host ? > > On EPYC, passing anything other than 47 will trigger error during SEV > guest initialization. The value of Cbit position is host dependent, the > value is readonly and can be obtained through the host CPUID. The > cbitpos must be same between guest and host. Please note that the pte's > in guest page table will need to use the cbitpos information to mark > the pages as encrypted. If cbit position given to the guest is different > from the host then guest will fail to execute. > > > > > In particular I thinking about possible migration scenario, where EPYC > > uses 47 by default but some $NEXT AMD CPU uses 48 by default. In that > > case we might want to use '47' on both CPUs if we need ability to live > > migrate between different host CPU generations. Would that be valid ? > > We will not be able to migrate SEV guests if cbit position does not > match between the source and destination hosts. Since during migration, > the destination guest is launched with same QEMU cli as source hence > cbitpos check in QEMU will catch it and fail the new launch. Optionally, > user can call query-sev-capabilities on both source and destination to > see if cbitpos is compatible before attempting to migrate the guest. > > > On the flip side, if the value really it strictly tied to the host > > CPU family and no deviation is permitted, could the kernel not just > > pick the right value automatically avoiding the config option ? > > > > I think doing so will be an issue for the migration. Consider your above > use case, a SEV guest is running on EPYC with cbitpos=47 and if we > migrate to some $NEXT AMD CPU which uses need to use cbitpos=48 and we > will fail to resume the guest on destination after migrating. Exactly, in other words these two options are part of the guest ABI, and QEMU promises to never make the guest ABI depend on the host hardware unless you're using "-cpu host". In theory we could make QEMU choose the right values automatically if we document very clearly that the default behavior is unsafe. But I would rather not take that risk and force management software to be aware of the gotchas involved in using SEV + live-migration.
On 08/03/2018 23:44, Eduardo Habkost wrote: >> I think doing so will be an issue for the migration. Consider your above >> use case, a SEV guest is running on EPYC with cbitpos=47 and if we >> migrate to some $NEXT AMD CPU which uses need to use cbitpos=48 and we >> will fail to resume the guest on destination after migrating. > > Exactly, in other words these two options are part of the guest > ABI, and QEMU promises to never make the guest ABI depend on the > host hardware unless you're using "-cpu host". This is not entirely true; while MAXPHYADDR is constant downstream unless using "-cpu host", in practice that behavior is wrong and a guest could misbehave if passed a MAXPHYADDR that is different from the host's. I think this is the same, and management software will have to live with it. Paolo > In theory we could make QEMU choose the right values > automatically if we document very clearly that the default > behavior is unsafe. But I would rather not take that risk and > force management software to be aware of the gotchas involved in > using SEV + live-migration.
On Tue, Mar 13, 2018 at 09:42:51AM +0100, Paolo Bonzini wrote: > On 08/03/2018 23:44, Eduardo Habkost wrote: > >> I think doing so will be an issue for the migration. Consider your above > >> use case, a SEV guest is running on EPYC with cbitpos=47 and if we > >> migrate to some $NEXT AMD CPU which uses need to use cbitpos=48 and we > >> will fail to resume the guest on destination after migrating. > > > > Exactly, in other words these two options are part of the guest > > ABI, and QEMU promises to never make the guest ABI depend on the > > host hardware unless you're using "-cpu host". > > This is not entirely true; while MAXPHYADDR is constant downstream > unless using "-cpu host", in practice that behavior is wrong and a guest > could misbehave if passed a MAXPHYADDR that is different from the host's. > > I think this is the same, and management software will have to live with it. > I think they are very far from being equivalent. In practice guests don't seem to mind if we don't perfectly emulate behavior that depend on MAXPHYADDR, and live-migration between hosts with different MAXPHYADDR works. But if you tell the guest the wrong C-bit location, guests are likely to rely on it and break. Migration between hosts with different C-bit locations won't work, will it?
On 13/03/2018 19:49, Eduardo Habkost wrote: >>> >>> Exactly, in other words these two options are part of the guest >>> ABI, and QEMU promises to never make the guest ABI depend on the >>> host hardware unless you're using "-cpu host". >> >> This is not entirely true; while MAXPHYADDR is constant downstream >> unless using "-cpu host", in practice that behavior is wrong and a guest >> could misbehave if passed a MAXPHYADDR that is different from the host's. >> >> I think this is the same, and management software will have to live with it. > > I think they are very far from being equivalent. Right, I only meant to say that guest ABI actually does depend on the host hardware, even outside of "-cpu host". > But if you tell the guest the wrong C-bit location, guests are > likely to rely on it and break. Migration between hosts with > different C-bit locations won't work, will it? It won't---but as long as the destination hosts fails fast when the C-bit location is wrong, it's okay. What matters is that we don't run guest code with the wrong C bit, as you noted. Paolo
On Tue, Mar 13, 2018 at 08:04:51PM +0100, Paolo Bonzini wrote: > On 13/03/2018 19:49, Eduardo Habkost wrote: > >>> > >>> Exactly, in other words these two options are part of the guest > >>> ABI, and QEMU promises to never make the guest ABI depend on the > >>> host hardware unless you're using "-cpu host". > >> > >> This is not entirely true; while MAXPHYADDR is constant downstream > >> unless using "-cpu host", in practice that behavior is wrong and a guest > >> could misbehave if passed a MAXPHYADDR that is different from the host's. > >> > >> I think this is the same, and management software will have to live with it. > > > > I think they are very far from being equivalent. > > Right, I only meant to say that guest ABI actually does depend on the > host hardware, even outside of "-cpu host". > > > But if you tell the guest the wrong C-bit location, guests are > > likely to rely on it and break. Migration between hosts with > > different C-bit locations won't work, will it? > > It won't---but as long as the destination hosts fails fast when the > C-bit location is wrong, it's okay. What matters is that we don't run > guest code with the wrong C bit, as you noted. Are you proposing we change the default to simply use cbitpos from the host? I would agree with this only if we make QEMU able to prevent live migration to a host with mismatching cbitpos.
* Eduardo Habkost (ehabkost@redhat.com) wrote: > On Tue, Mar 13, 2018 at 08:04:51PM +0100, Paolo Bonzini wrote: > > On 13/03/2018 19:49, Eduardo Habkost wrote: > > >>> > > >>> Exactly, in other words these two options are part of the guest > > >>> ABI, and QEMU promises to never make the guest ABI depend on the > > >>> host hardware unless you're using "-cpu host". > > >> > > >> This is not entirely true; while MAXPHYADDR is constant downstream > > >> unless using "-cpu host", in practice that behavior is wrong and a guest > > >> could misbehave if passed a MAXPHYADDR that is different from the host's. > > >> > > >> I think this is the same, and management software will have to live with it. > > > > > > I think they are very far from being equivalent. > > > > Right, I only meant to say that guest ABI actually does depend on the > > host hardware, even outside of "-cpu host". > > > > > But if you tell the guest the wrong C-bit location, guests are > > > likely to rely on it and break. Migration between hosts with > > > different C-bit locations won't work, will it? > > > > It won't---but as long as the destination hosts fails fast when the > > C-bit location is wrong, it's okay. What matters is that we don't run > > guest code with the wrong C bit, as you noted. > > Are you proposing we change the default to simply use cbitpos > from the host? Hmm I don't like that idea; as an option that's fine, as the only way it's not. > I would agree with this only if we make QEMU able to prevent live > migration to a host with mismatching cbitpos. Yeh; especially since I suspect debugging stuff with a failed SEV migration like that is going to be really hard. Dave > -- > Eduardo -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt index 72a92b6c6353..05266fd41b23 100644 --- a/docs/amd-memory-encryption.txt +++ b/docs/amd-memory-encryption.txt @@ -35,10 +35,21 @@ in bad measurement). The guest policy is a 4-byte data structure containing several flags that restricts what can be done on running SEV guest. See KM Spec section 3 and 6.2 for more details. +The guest policy can be provided via the 'policy' property (see below) + +# ${QEMU} \ + sev-guest,id=sev0,policy=0x1...\ + Guest owners provided DH certificate and session parameters will be used to establish a cryptographic session with the guest owner to negotiate keys used for the attestation. +The DH certificate and session blob can be provided via 'dh-cert-file' and +'session-file' property (see below + +# ${QEMU} \ + sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2> + LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context created via LAUNCH_START command. If required, this command can be called multiple times to encrypt different memory regions. The command also calculates @@ -59,6 +70,12 @@ context. See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the complete flow chart. +To launch a SEV guest + +# ${QEMU} \ + -machine ...,memory-encryption=sev0 \ + -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1 + Debugging ----------- Since memory contents of SEV guest is encrypted hence hypervisor access to the diff --git a/qemu-options.hx b/qemu-options.hx index 4c280142c52c..6113bce08a8c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4353,6 +4353,50 @@ contents of @code{iv.b64} to the second secret data=$SECRET,iv=$(<iv.b64) @end example +@item -object sev-guest,id=@var{id},cbitpos=@var{cbitpos},reduced-phys-bits=@var{val},[sev-device=@var{string},policy=@var{policy},handle=@var{handle},dh-cert-file=@var{file},session-file=@var{file}] + +Create a Secure Encrypted Virtualization (SEV) guest object, which can be used +to provide the guest memory encryption support on AMD processors. + +When memory encryption is enabled, one of the physical address bit (aka the +C-bit) is utilized to mark if a memory page is protected. The @option{cbitpos} +is used to provide the C-bit position. The C-bit position is Host family dependent +hence user must provide this value. On EPYC, the value should be 47. + +When memory encryption is enabled, we loose certain bits in physical address space. +The @option{reduced-phys-bits} is used to provide the number of bits we loose in +physical address space. Similar to C-bit, the value is Host family dependent. +On EPYC, the value should be 5. + +The @option{sev-device} provides the device file to use for communicating with +the SEV firmware running inside AMD Secure Processor. The default device is +'/dev/sev'. If hardware supports memory encryption then /dev/sev devices are +created by CCP driver. + +The @option{policy} provides the guest policy to be enforced by the SEV firmware +and restrict what configuration and operational commands can be performed on this +guest by the hypervisor. The policy should be provided by the guest owner and is +bound to the guest and cannot be changed throughout the lifetime of the guest. +The default is 0. + +If guest @option{policy} allows sharing the key with another SEV guest then +@option{handle} can be use to provide handle of the guest from which to share +the key. + +The @option{dh-cert-file} and @option{session-file} provides the guest owner's +Public Diffie-Hillman key defined in SEV spec. The PDH and session parameters +are used for establishing a cryptographic session with the guest owner to +negotiate keys used for attestation. The file must be encoded in base64. + +e.g to launch a SEV guest +@example + # $QEMU \ + ...... + -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=5 \ + -machine ...,memory-encryption=sev0 + ..... + +@end example @end table ETEXI diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index f5c6ef20a7bb..76aeaeae2750 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -4,7 +4,7 @@ obj-$(CONFIG_TCG) += bpt_helper.o cc_helper.o excp_helper.o fpu_helper.o obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o mpx_helper.o obj-$(CONFIG_TCG) += seg_helper.o smm_helper.o svm_helper.o obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o -obj-$(CONFIG_KVM) += kvm.o hyperv.o +obj-$(CONFIG_KVM) += kvm.o hyperv.o sev.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o # HAX support ifdef CONFIG_WIN32 diff --git a/target/i386/sev.c b/target/i386/sev.c new file mode 100644 index 000000000000..ab42e4a456d2 --- /dev/null +++ b/target/i386/sev.c @@ -0,0 +1,228 @@ +/* + * QEMU SEV support + * + * Copyright Advanced Micro Devices 2016-2018 + * + * Author: + * Brijesh Singh <brijesh.singh@amd.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "qemu/base64.h" +#include "sysemu/kvm.h" +#include "sev_i386.h" +#include "sysemu/sysemu.h" + +#define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ +#define DEFAULT_SEV_DEVICE "/dev/sev" + +static void +qsev_guest_finalize(Object *obj) +{ +} + +static char * +qsev_guest_get_session_file(Object *obj, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + return s->session_file ? g_strdup(s->session_file) : NULL; +} + +static void +qsev_guest_set_session_file(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + s->session_file = g_strdup(value); +} + +static char * +qsev_guest_get_dh_cert_file(Object *obj, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + return g_strdup(s->dh_cert_file); +} + +static void +qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + s->dh_cert_file = g_strdup(value); +} + +static char * +qsev_guest_get_sev_device(Object *obj, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + return g_strdup(sev->sev_device); +} + +static void +qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + sev->sev_device = g_strdup(value); +} + +static void +qsev_guest_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_str(oc, "sev-device", + qsev_guest_get_sev_device, + qsev_guest_set_sev_device, + NULL); + object_class_property_set_description(oc, "sev-device", + "SEV device to use", NULL); + object_class_property_add_str(oc, "dh-cert-file", + qsev_guest_get_dh_cert_file, + qsev_guest_set_dh_cert_file, + NULL); + object_class_property_set_description(oc, "dh-cert-file", + "guest owners DH certificate (encoded with base64)", NULL); + object_class_property_add_str(oc, "session-file", + qsev_guest_get_session_file, + qsev_guest_set_session_file, + NULL); + object_class_property_set_description(oc, "session-file", + "guest owners session parameters (encoded with base64)", NULL); +} + +static void +qsev_guest_set_handle(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->handle = value; +} + +static void +qsev_guest_set_policy(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->policy = value; +} + +static void +qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->cbitpos = value; +} + +static void +qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->reduced_phys_bits = value; +} + +static void +qsev_guest_get_policy(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->policy; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_get_handle(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->handle; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->cbitpos; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->reduced_phys_bits; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_init(Object *obj) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE); + sev->policy = DEFAULT_GUEST_POLICY; + object_property_add(obj, "policy", "uint32", qsev_guest_get_policy, + qsev_guest_set_policy, NULL, NULL, NULL); + object_property_add(obj, "handle", "uint32", qsev_guest_get_handle, + qsev_guest_set_handle, NULL, NULL, NULL); + object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos, + qsev_guest_set_cbitpos, NULL, NULL, NULL); + object_property_add(obj, "reduced-phys-bits", "uint32", + qsev_guest_get_reduced_phys_bits, + qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL); +} + +/* sev guest info */ +static const TypeInfo qsev_guest_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QSEV_GUEST_INFO, + .instance_size = sizeof(QSevGuestInfo), + .instance_finalize = qsev_guest_finalize, + .class_size = sizeof(QSevGuestInfoClass), + .class_init = qsev_guest_class_init, + .instance_init = qsev_guest_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void +sev_register_types(void) +{ + type_register_static(&qsev_guest_info); +} + +type_init(sev_register_types); diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h new file mode 100644 index 000000000000..caf879c3b874 --- /dev/null +++ b/target/i386/sev_i386.h @@ -0,0 +1,61 @@ +/* + * QEMU Secure Encrypted Virutualization (SEV) support + * + * Copyright: Advanced Micro Devices, 2016-2018 + * + * Authors: + * Brijesh Singh <brijesh.singh@amd.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_SEV_I386_H +#define QEMU_SEV_I386_H + +#include "qom/object.h" +#include "qapi/error.h" +#include "sysemu/kvm.h" +#include "qemu/error-report.h" + +#define SEV_POLICY_NODBG 0x1 +#define SEV_POLICY_NOKS 0x2 +#define SEV_POLICY_ES 0x4 +#define SEV_POLICY_NOSEND 0x8 +#define SEV_POLICY_DOMAIN 0x10 +#define SEV_POLICY_SEV 0x20 + +#define TYPE_QSEV_GUEST_INFO "sev-guest" +#define QSEV_GUEST_INFO(obj) \ + OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO) + +typedef struct QSevGuestInfo QSevGuestInfo; +typedef struct QSevGuestInfoClass QSevGuestInfoClass; + +/** + * QSevGuestInfo: + * + * The QSevGuestInfo object is used for creating a SEV guest. + * + * # $QEMU \ + * -object sev-guest,id=sev0 \ + * -machine ...,memory-encryption=sev0 + */ +struct QSevGuestInfo { + Object parent_obj; + + char *sev_device; + uint32_t policy; + uint32_t handle; + char *dh_cert_file; + char *session_file; + uint32_t cbitpos; + uint32_t reduced_phys_bits; +}; + +struct QSevGuestInfoClass { + ObjectClass parent_class; +}; + +#endif
Add a new memory encryption object 'sev-guest'. The object will be used to create enrypted VMs on AMD EPYC CPU. The object provides the properties to pass guest owner's public Diffie-hellman key, guest policy and session information required to create the memory encryption context within the SEV firmware. e.g to launch SEV guest # $QEMU \ -object sev-guest,id=sev0 \ -machine ....,memory-encryption=sev0 Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Richard Henderson <rth@twiddle.net> Cc: Eduardo Habkost <ehabkost@redhat.com> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> --- docs/amd-memory-encryption.txt | 17 +++ qemu-options.hx | 44 ++++++++ target/i386/Makefile.objs | 2 +- target/i386/sev.c | 228 +++++++++++++++++++++++++++++++++++++++++ target/i386/sev_i386.h | 61 +++++++++++ 5 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 target/i386/sev.c create mode 100644 target/i386/sev_i386.h