diff mbox

[v12,08/28] target/i386: add Secure Encrypted Virtulization (SEV) object

Message ID 20180308124901.83533-9-brijesh.singh@amd.com (mailing list archive)
State New, archived
Headers show

Commit Message

Brijesh Singh March 8, 2018, 12:48 p.m. UTC
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

Comments

Daniel P. Berrangé March 8, 2018, 4:49 p.m. UTC | #1
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
Brijesh Singh March 8, 2018, 10:22 p.m. UTC | #2
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
Eduardo Habkost March 8, 2018, 10:44 p.m. UTC | #3
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.
Paolo Bonzini March 13, 2018, 8:42 a.m. UTC | #4
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.
Eduardo Habkost March 13, 2018, 6:49 p.m. UTC | #5
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?
Paolo Bonzini March 13, 2018, 7:04 p.m. UTC | #6
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
Eduardo Habkost March 13, 2018, 7:20 p.m. UTC | #7
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.
Dr. David Alan Gilbert March 13, 2018, 7:49 p.m. UTC | #8
* 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 mbox

Patch

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