QEMU >= 2.12 provides 'sev-guest' object which is used to launch encrypted
VMs on AMD platform using SEV feature. The various inputs required to
launch SEV guest is provided through the <launch-security> tag. A typical
SEV guest launch command line looks like this:
# $QEMU ...\
-object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=5 ...\
-machine memory-encryption=sev0 \
Signed-off-by: Brijesh Singh <brijesh.singh(a)amd.com>
---
src/qemu/qemu_command.c | 35 +++++++++++++++++++++++++++++
src/qemu/qemu_process.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 682d714..55bbfa2 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -7405,6 +7405,9 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
virQEMUCapsGet(qemuCaps, QEMU_CAPS_LOADPARM))
qemuAppendLoadparmMachineParm(&buf, def);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST) && def->sev)
+ virBufferAddLit(&buf, ",memory-encryption=sev0");
+
virCommandAddArgBuffer(cmd, &buf);
}
@@ -9750,6 +9753,35 @@ qemuBuildTPMCommandLine(virCommandPtr cmd,
return 0;
}
+static void
+qemuBuildSevCommandLine(virDomainObjPtr vm, virCommandPtr cmd,
+ virDomainSevDefPtr sev)
+{
+ virBuffer obj = VIR_BUFFER_INITIALIZER;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ char *path = NULL;
+
+ VIR_DEBUG("policy=0x%x cbitpos=%d reduced_phys_bits=%d",
+ sev->policy, sev->cbitpos, sev->reduced_phys_bits);
+
+ virBufferAsprintf(&obj, "sev-guest,id=sev0,cbitpos=%d",
sev->cbitpos);
+ virBufferAsprintf(&obj, ",reduced-phys-bits=%d",
sev->reduced_phys_bits);
+ virBufferAsprintf(&obj, ",policy=0x%x", sev->policy);
+
+ if (sev->dh_cert) {
+ ignore_value(virAsprintf(&path, "%s/dh_cert.base64",
priv->libDir));
+ virBufferAsprintf(&obj, ",dh-cert-file=%s", path);
+ VIR_FREE(path);
+ }
+
+ if (sev->session) {
+ ignore_value(virAsprintf(&path, "%s/session.base64",
priv->libDir));
+ virBufferAsprintf(&obj, ",session-file=%s", path);
+ VIR_FREE(path);
+ }
+
+ virCommandAddArgList(cmd, "-object", virBufferContentAndReset(&obj),
NULL);
+}
static int
qemuBuildVMCoreInfoCommandLine(virCommandPtr cmd,
@@ -10195,6 +10227,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
if (qemuBuildVMCoreInfoCommandLine(cmd, def, qemuCaps) < 0)
goto error;
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST) && def->sev)
+ qemuBuildSevCommandLine(vm, cmd, def->sev);
+
if (snapshot)
virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index c0105c8..0c93f15 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -5745,6 +5745,61 @@ qemuProcessPrepareDomain(virQEMUDriverPtr driver,
return ret;
}
+static int
+qemuBuildSevCreateFile(const char *configDir, const char *name,
+ const char *data)
+{
+ char *configFile;
+
+ if (!(configFile = virFileBuildPath(configDir, name, ".base64")))
+ return -1;
+
+ if (virFileRewriteStr(configFile, S_IRUSR | S_IWUSR, data) < 0) {
+ virReportSystemError(errno, _("failed to write data to config
'%s'"),
+ configFile);
+ goto error;
+ }
+
+ VIR_FREE(configFile);
+ return 0;
+
+ error:
+ VIR_FREE(configFile);
+ return -1;
+}
+
+static int
+qemuProcessPrepareSevGuestInput(virDomainObjPtr vm)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainDefPtr def = vm->def;
+ virQEMUCapsPtr qemuCaps = priv->qemuCaps;
+ virDomainSevDefPtr sev = def->sev;
+
+ if (!sev)
+ return 0;
+
+ VIR_DEBUG("Prepare SEV guest");
+
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Domain %s asked for 'sev' launch but "
+ "QEMU does not support SEV feature"),
vm->def->name);
+ return -1;
+ }
+
+ if (sev->dh_cert) {
+ if (qemuBuildSevCreateFile(priv->libDir, "dh_cert", sev->dh_cert)
< 0)
+ return -1;
+ }
+
+ if (sev->session) {
+ if (qemuBuildSevCreateFile(priv->libDir, "session", sev->session)
< 0)
+ return -1;
+ }
+
+ return 0;
+}
static int
qemuProcessPrepareHostStorage(virQEMUDriverPtr driver,
@@ -5870,6 +5925,9 @@ qemuProcessPrepareHost(virQEMUDriverPtr driver,
if (qemuProcessPrepareHostStorage(driver, vm, flags) < 0)
goto cleanup;
+ if (qemuProcessPrepareSevGuestInput(vm) < 0)
+ goto cleanup;
+
ret = 0;
cleanup:
virObjectUnref(cfg);
--
2.7.4