[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 09/16] common: Introduce confidential computing infrastructure



Introduce a subsystem that is used for future confidential computing
platforms. This subsystem manages and provides hooks for domain management
and exposes various informations for toolstack (COCO platform, supported
features, ...).

Add a domain creation flag to build a confidential computing guest.

Signed-off-by: Teddy Astie <teddy.astie@xxxxxxxxxx>
---
 xen/arch/x86/domain.c         |   4 +
 xen/arch/x86/hvm/hvm.c        |  10 ++-
 xen/common/Kconfig            |   5 ++
 xen/common/Makefile           |   1 +
 xen/common/coco.c             | 134 ++++++++++++++++++++++++++++++++++
 xen/common/domain.c           |  41 ++++++++++-
 xen/include/hypercall-defs.c  |   2 +
 xen/include/public/domctl.h   |   5 +-
 xen/include/public/hvm/coco.h |  65 +++++++++++++++++
 xen/include/public/xen.h      |   1 +
 xen/include/xen/coco.h        |  88 ++++++++++++++++++++++
 xen/include/xen/sched.h       |  10 +++
 12 files changed, 363 insertions(+), 3 deletions(-)
 create mode 100644 xen/common/coco.c
 create mode 100644 xen/include/public/hvm/coco.h
 create mode 100644 xen/include/xen/coco.h

diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index f197dad4c0..a5783154ad 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -12,6 +12,7 @@
  */
 
 #include <xen/acpi.h>
+#include <xen/coco.h>
 #include <xen/compat.h>
 #include <xen/console.h>
 #include <xen/cpu.h>
@@ -948,6 +949,9 @@ void arch_domain_destroy(struct domain *d)
     free_xenheap_page(d->shared_info);
     cleanup_domain_irq_mapping(d);
 
+    if ( is_coco_domain(d) )
+        coco_domain_destroy(d);
+
     psr_domain_free(d);
 }
 
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 625ae2098b..e1bcf8e086 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -15,6 +15,7 @@
 #include <xen/sched.h>
 #include <xen/irq.h>
 #include <xen/softirq.h>
+#include <xen/coco.h>
 #include <xen/domain.h>
 #include <xen/domain_page.h>
 #include <xen/hypercall.h>
@@ -702,7 +703,11 @@ int hvm_domain_initialise(struct domain *d,
     if ( rc )
         goto fail2;
 
-    rc = hvm_asid_alloc(&d->arch.hvm.asid);
+    if ( is_coco_domain(d) && d->coco_ops && d->coco_ops->asid_alloc )
+        rc = d->coco_ops->asid_alloc(d, &d->arch.hvm.asid);
+    else
+        rc = hvm_asid_alloc(&d->arch.hvm.asid);
+
     if ( rc )
         goto fail2;
 
@@ -710,6 +715,9 @@ int hvm_domain_initialise(struct domain *d,
     if ( rc != 0 )
         goto fail2;
 
+    if ( is_coco_domain(d) )
+        coco_domain_initialise(d);
+
     return 0;
 
  fail2:
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 6d43be2e6e..1ddb73e707 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -576,4 +576,9 @@ config BUDDY_ALLOCATOR_SIZE
          Amount of memory reserved for the buddy allocator to serve Xen heap,
          working alongside the colored one.
 
+config COCO
+       bool "Enable COnfidential COmputing support for guests" if EXPERT
+       default n
+       help
+         Allows to run guests in private encrypted memory space.
 endmenu
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 98f0873056..4409510fc0 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_GENERIC_BUG_FRAME) += bug.o
 obj-$(CONFIG_HYPFS_CONFIG) += config_data.o
 obj-$(CONFIG_CORE_PARKING) += core_parking.o
 obj-y += cpu.o
+obj-$(CONFIG_COCO) += coco.o
 obj-$(CONFIG_DEBUG_TRACE) += debugtrace.o
 obj-$(CONFIG_HAS_DEVICE_TREE) += device.o
 obj-$(filter-out $(CONFIG_X86),$(CONFIG_ACPI)) += device.o
diff --git a/xen/common/coco.c b/xen/common/coco.c
new file mode 100644
index 0000000000..d9bd17628d
--- /dev/null
+++ b/xen/common/coco.c
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * General confidential computing functions.
+ */
+ 
+#include <xen/coco.h>
+#include <xen/errno.h>
+#include <xen/domain.h>
+#include <xen/domain_page.h>
+#include <xen/guest_access.h>
+#include <xen/hypercall.h>
+#include <xen/sched.h>
+#include <xen/sections.h>
+#include <xen/types.h>
+
+#include <asm/p2m.h>
+
+#include <public/hvm/coco.h>
+
+static __ro_after_init struct coco_ops *coco_ops;
+__read_mostly struct coco_platform_status platform_status;
+
+void __init coco_register_ops(struct coco_ops *ops)
+{
+    coco_ops = ops;
+}
+
+int __init coco_init(void)
+{
+    int rc = 0;
+
+    if ( coco_ops )
+        printk("coco: Using '%s'\n", coco_ops->name);
+    else
+    {
+        printk("coco: No platform found\n");
+        return 0;
+    }
+
+    if ( coco_ops->init )
+    {
+        rc = coco_ops->init();
+        
+        if ( rc )
+        {
+            printk("coco: Unable to initialize coco platform (%d)", rc);
+            goto err;
+        }
+    }
+
+    rc = coco_ops->get_platform_status(&platform_status);
+    if ( rc )
+    {
+        printk("coco: Unable to get platform status\n");
+        goto err;
+    }
+
+    return 0;
+
+err:
+    /* Disable confidential computing if initialization failed. */
+    coco_ops = NULL;
+    return rc;
+}
+
+void coco_set_domain_ops(struct domain *d)
+{
+    ASSERT(is_coco_domain(d));
+
+    d->coco_ops = coco_ops->get_domain_ops(d);
+}
+
+int coco_prepare_initial_memory(struct domain *d, gfn_t gfn, size_t page_count)
+{
+    /* TODO: Check prepare_initial_memory constraints (no dangling mapping). */
+
+    if ( d->coco_ops->prepare_initial_mem )
+        return d->coco_ops->prepare_initial_mem(d, gfn, page_count);
+    
+    return 0;
+}
+
+long coco_op_prepare_initial_mem(struct coco_prepare_initial_mem arg)
+{
+    long rc = 0;
+    struct domain *d = get_domain_by_id(arg.domid);
+
+    if ( !d )
+        return -ENOENT;
+    
+    if ( !is_coco_domain(d) )
+    {
+        rc = -EOPNOTSUPP;
+        goto out;
+    }
+
+    rc = coco_prepare_initial_memory(d, arg.gfn, arg.count);
+
+out:
+    put_domain(d);
+    return rc;
+}
+
+long do_coco_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
+{
+    if ( !is_hardware_domain(current->domain) )
+        return -EPERM;
+
+    switch (cmd)
+    {
+        case XEN_COCO_platform_status:
+        {
+            if ( copy_to_guest(arg, &platform_status, 1) )
+                return -EFAULT;
+
+            return 0;
+        }
+        
+        case XEN_COCO_prepare_initial_mem:
+        {
+            struct coco_prepare_initial_mem prepare_initial_mem;
+
+            if ( copy_from_guest(&prepare_initial_mem, arg, 1) )
+                return -EFAULT;
+
+            return coco_op_prepare_initial_mem(prepare_initial_mem);
+        }
+
+        default:
+            return -ENOSYS;
+    }
+}
+
+__initcall(coco_init);
\ No newline at end of file
diff --git a/xen/common/domain.c b/xen/common/domain.c
index abf1969e60..c29d6efd29 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -4,6 +4,7 @@
  * Generic domain-handling functions.
  */
 
+#include <xen/coco.h>
 #include <xen/compat.h>
 #include <xen/init.h>
 #include <xen/lib.h>
@@ -716,17 +717,51 @@ static int sanitise_domain_config(struct 
xen_domctl_createdomain *config)
     bool hap = config->flags & XEN_DOMCTL_CDF_hap;
     bool iommu = config->flags & XEN_DOMCTL_CDF_iommu;
     bool vpmu = config->flags & XEN_DOMCTL_CDF_vpmu;
+    bool coco = config->flags & XEN_DOMCTL_CDF_coco;
 
     if ( config->flags &
          ~(XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
            XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
            XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
-           XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu) )
+           XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu | 
XEN_DOMCTL_CDF_coco) )
     {
         dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
         return -EINVAL;
     }
 
+    if ( coco )
+    {
+        if ( !IS_ENABLED(CONFIG_COCO) )
+        {
+            dprintk(XENLOG_INFO, "COCO support is compiled out\n");
+            return -EINVAL;
+        }
+
+        if ( !coco_is_supported() )
+        {
+            dprintk(XENLOG_INFO, "COCO is not available\n");
+            return -EINVAL;
+        }
+    
+        if ( !hvm )
+        {
+            dprintk(XENLOG_INFO, "COCO requested for non-HVM guest\n");
+            return -EINVAL;
+        }
+
+        if ( !hap )
+        {
+            dprintk(XENLOG_INFO, "COCO cannot work without HAP\n");
+            return -EINVAL;
+        }
+
+        if ( config->flags & XEN_DOMCTL_CDF_nested_virt )
+        {
+            dprintk(XENLOG_INFO, "Nested virtualization isn't supported with 
COCO\n");
+            return -EINVAL;
+        }
+    }
+
     if ( config->grant_opts & ~XEN_DOMCTL_GRANT_version_mask )
     {
         dprintk(XENLOG_INFO, "Unknown grant options %#x\n", 
config->grant_opts);
@@ -836,6 +871,9 @@ struct domain *domain_create(domid_t domid,
     /* Holding CDF_* internal flags. */
     d->cdf = flags;
 
+    if ( is_coco_domain(d) )
+        coco_set_domain_ops(d);
+
     TRACE_TIME(TRC_DOM0_DOM_ADD, d->domain_id);
 
     lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid);
@@ -1617,6 +1655,7 @@ int domain_unpause_by_systemcontroller(struct domain *d)
     {
         d->creation_finished = true;
         arch_domain_creation_finished(d);
+        coco_domain_creation_finished(d); /* TODO: or before arch_* ? */
     }
 
     domain_unpause(d);
diff --git a/xen/include/hypercall-defs.c b/xen/include/hypercall-defs.c
index 7720a29ade..6c01a9e395 100644
--- a/xen/include/hypercall-defs.c
+++ b/xen/include/hypercall-defs.c
@@ -209,6 +209,7 @@ hypfs_op(unsigned int cmd, const char *arg1, unsigned long 
arg2, void *arg3, uns
 #ifdef CONFIG_X86
 xenpmu_op(unsigned int op, xen_pmu_params_t *arg)
 #endif
+coco_op(unsigned int cmd, void *arg)
 
 #ifdef CONFIG_PV
 caller: pv64
@@ -295,5 +296,6 @@ mca                                do       do       -      
  -        -
 #ifndef CONFIG_PV_SHIM_EXCLUSIVE
 paging_domctl_cont                 do       do       do       do       -
 #endif
+coco_op                            do       do       do       do       do
 
 #endif /* !CPPCHECK */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 5b2063eed9..f4f69556b6 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -67,8 +67,11 @@ struct xen_domctl_createdomain {
 /* Should we expose the vPMU to the guest? */
 #define XEN_DOMCTL_CDF_vpmu           (1U << 7)
 
+#define _XEN_DOMCTL_CDF_coco         8
+#define XEN_DOMCTL_CDF_coco          (1U << _XEN_DOMCTL_CDF_coco)
+
 /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
-#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_vpmu
+#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_coco
 
     uint32_t flags;
 
diff --git a/xen/include/public/hvm/coco.h b/xen/include/public/hvm/coco.h
new file mode 100644
index 0000000000..2e23d91e12
--- /dev/null
+++ b/xen/include/public/hvm/coco.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __XEN_PUBLIC_HVM_COCO_H__
+#define __XEN_PUBLIC_HVM_COCO_H__
+
+#include "../xen.h"
+
+#define XEN_COCO_platform_status 0
+
+/**
+ * XEN_COCO_platform_status: Get the status of confidential computing platform.
+ *
+ * Query informations regarding the current confidential computing platform.
+ *
+ * Confidential computing is supposed working as long as 
COCO_STATUS_FLAG_SUPPORTED bit
+ * is set, and additionally security-supported only if COCO_STATUS_FLAG_UNSAFE 
bit
+ * is cleared.
+ *
+ * If COCO_PLATFORM_FLAG_UNSAFE is set but COCO_PLATFORM_FLAG_SUPPORTED is not,
+ * then confidential computing is explicitly present but intentionally disabled
+ * or forbidden by policy.
+ */
+struct coco_platform_status {
+#define COCO_PLATFORM_none        0 /* None */
+#define COCO_PLATFORM_amd_sev     1 /* AMD Secure Encrypted Virtualization */
+#define COCO_PLATFORM_intel_tdx   2 /* Intel Trust Domain Extensions */
+#define COCO_PLATFORM_arm_rme     3 /* ARM Realm Management Extension */
+    uint32_t platform; /* OUT */
+
+#define COCO_PLATFORM_FLAG_sev_es  (1 << 0) /* AMD SEV Encrypted State */
+#define COCO_PLATFORM_FLAG_sev_snp (1 << 1) /* AMD SEV Secure Nested Paging */
+#define COCO_PLATFORM_FLAG_sev_tio (1 << 2) /* AMD SEV Trusted I/O */
+    uint32_t platform_flags; /* OUT */
+
+#define COCO_STATUS_FLAG_supported (1 << 0) /* Confidential computing is 
supported and usable */
+#define COCO_STATUS_FLAG_unsafe    (1 << 1) /* Confidential computing is 
unsafe (e.g debug mode) */
+    uint32_t flags;    /* OUT */
+    uint32_t features; /* OUT */
+
+    uint32_t version_major; /* OUT */
+    uint32_t version_minor; /* OUT */
+};
+typedef struct coco_platform_status coco_platform_status_t;
+DEFINE_XEN_GUEST_HANDLE(coco_platform_status_t);
+
+#define XEN_COCO_prepare_initial_mem 1
+
+/**
+ * XEN_COCO_prepare_initial_mem: Prepare early memory pages of a guest
+ * 
+ * During guest construction, the confidential computing platform may require 
memory
+ * to be prepared (e.g., encrypted) before the guest is started.
+ * 
+ * After preparation, any further access to these pages is invalid, as they 
may be
+ * encrypted, sealed, or tracked by the platform.
+ */
+struct coco_prepare_initial_mem {
+    domid_t domid;      /* IN */
+    uint16_t _rsvd[3];  /* ZERO */
+    uint64_t gfn;       /* IN */
+    uint64_t count;     /* IN */
+};
+typedef struct coco_prepare_initial_mem coco_prepare_initial_mem_t;
+DEFINE_XEN_GUEST_HANDLE(coco_prepare_initial_mem_t);
+
+#endif /* __XEN_PUBLIC_HVM_COCO_H__ */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 82b9c05a76..e656d6f617 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -118,6 +118,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
 #define __HYPERVISOR_xenpmu_op            40
 #define __HYPERVISOR_dm_op                41
 #define __HYPERVISOR_hypfs_op             42
+#define __HYPERVISOR_coco_op              43
 
 /* Architecture-specific hypercall definitions. */
 #define __HYPERVISOR_arch_0               48
diff --git a/xen/include/xen/coco.h b/xen/include/xen/coco.h
new file mode 100644
index 0000000000..2ae43995ec
--- /dev/null
+++ b/xen/include/xen/coco.h
@@ -0,0 +1,88 @@
+#ifndef _XEN_COCO_H
+#define _XEN_COCO_H
+
+#include <asm/nospec.h>
+
+#include <xen/stdint.h>
+#include <xen/sched.h>
+
+#include <public/hvm/coco.h>
+
+extern __read_mostly struct coco_platform_status platform_status;
+
+struct coco_domain_ops {
+    int (*prepare_initial_mem)(struct domain *d, gfn_t gfn, size_t page_count);
+    /* domain_creation_finished, ... */    
+
+    /* HVM domain hooks */
+    int (*domain_initialise)(struct domain *d);
+    int (*domain_creation_finished)(struct domain *d);
+    void (*domain_destroy)(struct domain *d);
+
+#ifdef CONFIG_X86
+    /* COCO-specific ASID allocation logic */
+    int (*asid_alloc)(struct domain *d, struct hvm_asid *asid);
+#endif
+};
+
+struct coco_ops {
+    const char *name;
+    
+    int (*init)(void);
+    int (*get_platform_status)(coco_platform_status_t *status);
+    struct coco_domain_ops *(*get_domain_ops)(struct domain *d);
+};
+
+void __init coco_register_ops(struct coco_ops *ops);
+int __init coco_init(void);
+void coco_set_domain_ops(struct domain *d);
+
+#ifdef CONFIG_COCO
+static inline bool coco_is_supported(void)
+{
+    return evaluate_nospec(platform_status.flags & COCO_STATUS_FLAG_supported);
+}
+
+static inline int coco_domain_initialise(struct domain *d)
+{
+    if ( d->coco_ops && d->coco_ops->domain_initialise )
+        return d->coco_ops->domain_initialise(d);
+
+    return 0;
+}
+
+static inline int coco_domain_creation_finished(struct domain *d)
+{
+    if ( d->coco_ops && d->coco_ops->domain_creation_finished )
+        return d->coco_ops->domain_creation_finished(d);
+
+    return 0;
+}
+
+static inline void coco_domain_destroy(struct domain *d)
+{
+    if ( d->coco_ops && d->coco_ops->domain_destroy )
+        d->coco_ops->domain_destroy(d);
+}
+#else
+static inline bool coco_is_supported(void)
+{
+    return false;
+}
+
+static inline int coco_domain_initialise(struct domain *d)
+{
+    return 0;
+}
+
+static inline int coco_domain_creation_finished(struct domain *d)
+{
+    return 0;
+}
+
+static inline void coco_domain_destroy(struct domain *d)
+{
+}
+#endif
+
+#endif /* _XEN_COCO_H */
\ No newline at end of file
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index f2f5a98534..c57bedc30a 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -630,6 +630,10 @@ struct domain
     struct argo_domain *argo;
 #endif
 
+#ifdef CONFIG_COCO
+    struct coco_domain_ops *coco_ops;
+#endif
+
     /*
      * Continuation information for domain_teardown().  All fields entirely
      * private.
@@ -1198,6 +1202,12 @@ static always_inline bool is_hvm_vcpu(const struct vcpu 
*v)
     return is_hvm_domain(v->domain);
 }
 
+static always_inline bool is_coco_domain(const struct domain *d)
+{
+    return IS_ENABLED(CONFIG_COCO) &&
+        evaluate_nospec(d->options & XEN_DOMCTL_CDF_coco);
+}
+
 static always_inline bool hap_enabled(const struct domain *d)
 {
     /* sanitise_domain_config() rejects HAP && !HVM */
-- 
2.49.0



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.